]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2064 in SNORT/snort3 from ~DAVMCPHE/snort3:hash_foo_2 to master
authorRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 6 Mar 2020 13:38:27 +0000 (13:38 +0000)
committerRuss Combs (rucombs) <rucombs@cisco.com>
Fri, 6 Mar 2020 13:38:27 +0000 (13:38 +0000)
Squashed commit of the following:

commit 649dd07dbd388d18c87bb0a8d1da755a1dff1a11
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Thu Mar 5 09:13:14 2020 -0500

    ips_manager: revert broken support for thread_reinit

commit 14333c503c2694e3d811097e84f14d1bd66dc701
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Thu Mar 5 08:12:25 2020 -0500

    flow_cache: fix memory deallocation bug due to inverted return value from hash release node

commit 5fe12ecd06e53b8239540fd51ad5a1527ddefa3d
Author: davis mcpherson <davmcphe@cisco.com>
Date:   Wed Mar 4 09:25:06 2020 -0500

    Revert "Merge pull request #2054 in SNORT/snort3 from ~DAVMCPHE/snort3:revert_hash_foo to master"

    This reverts commit 6b385a10a4c012df7c8dd682b72958ae8e9d9adb.

147 files changed:
src/detection/detection_options.cc
src/detection/detection_options.h
src/detection/fp_create.cc
src/detection/signature.cc
src/detection/tag.cc
src/file_api/file_cache.cc
src/file_api/file_cache.h
src/file_api/file_identifier.cc
src/file_api/file_identifier.h
src/file_api/file_module.cc
src/file_api/file_service.cc
src/filters/sfrf.cc
src/filters/sfthd.cc
src/flow/expect_cache.cc
src/flow/flow_cache.cc
src/flow/flow_key.cc
src/flow/flow_key.h
src/flow/test/CMakeLists.txt
src/framework/ips_option.cc
src/hash/CMakeLists.txt
src/hash/ghash.cc
src/hash/ghash.h
src/hash/hash_defs.h
src/hash/hash_key_operations.cc [moved from src/hash/hashfcn.cc with 65% similarity]
src/hash/hash_key_operations.h [moved from src/hash/hashfcn.h with 83% similarity]
src/hash/hash_lru_cache.cc [new file with mode: 0644]
src/hash/hash_lru_cache.h [new file with mode: 0644]
src/hash/test/CMakeLists.txt
src/hash/test/ghash_test.cc
src/hash/test/hash_lru_cache_test.cc [new file with mode: 0644]
src/hash/test/xhash_test.cc
src/hash/test/zhash_test.cc [new file with mode: 0644]
src/hash/xhash.cc
src/hash/xhash.h
src/hash/zhash.cc
src/hash/zhash.h
src/ips_options/ips_ack.cc
src/ips_options/ips_asn1.cc
src/ips_options/ips_base64.cc
src/ips_options/ips_ber_data.cc
src/ips_options/ips_ber_skip.cc
src/ips_options/ips_bufferlen.cc
src/ips_options/ips_byte_extract.cc
src/ips_options/ips_byte_jump.cc
src/ips_options/ips_byte_math.cc
src/ips_options/ips_byte_test.cc
src/ips_options/ips_content.cc
src/ips_options/ips_cvs.cc
src/ips_options/ips_dsize.cc
src/ips_options/ips_file_type.cc
src/ips_options/ips_flags.cc
src/ips_options/ips_flow.cc
src/ips_options/ips_flowbits.cc
src/ips_options/ips_fragbits.cc
src/ips_options/ips_fragoffset.cc
src/ips_options/ips_hash.cc
src/ips_options/ips_icmp_id.cc
src/ips_options/ips_icmp_seq.cc
src/ips_options/ips_icode.cc
src/ips_options/ips_id.cc
src/ips_options/ips_ip_proto.cc
src/ips_options/ips_ipopts.cc
src/ips_options/ips_isdataat.cc
src/ips_options/ips_itype.cc
src/ips_options/ips_luajit.cc
src/ips_options/ips_pcre.cc
src/ips_options/ips_regex.cc
src/ips_options/ips_replace.cc
src/ips_options/ips_rpc.cc
src/ips_options/ips_sd_pattern.cc
src/ips_options/ips_seq.cc
src/ips_options/ips_session.cc
src/ips_options/ips_so.cc
src/ips_options/ips_tos.cc
src/ips_options/ips_ttl.cc
src/ips_options/ips_window.cc
src/log/messages.cc
src/log/messages.h
src/main.cc
src/main/snort_config.cc
src/main/snort_config.h
src/mime/file_mime_process.cc
src/network_inspectors/appid/ips_appid_option.cc
src/network_inspectors/perf_monitor/flow_ip_tracker.cc
src/network_inspectors/perf_monitor/perf_monitor.cc
src/network_inspectors/perf_monitor/perf_pegs.h
src/network_inspectors/port_scan/ps_detect.cc
src/parser/parser.cc
src/ports/port_object.cc
src/ports/port_object.h
src/ports/port_object2.cc
src/ports/port_object2.h
src/ports/port_table.cc
src/ports/port_table.h
src/ports/port_var_table.cc
src/ports/port_var_table.h
src/service_inspectors/cip/ips_cip_attribute.cc
src/service_inspectors/cip/ips_cip_class.cc
src/service_inspectors/cip/ips_cip_connpathclass.cc
src/service_inspectors/cip/ips_cip_enipcommand.cc
src/service_inspectors/cip/ips_cip_enipreq.cc
src/service_inspectors/cip/ips_cip_eniprsp.cc
src/service_inspectors/cip/ips_cip_instance.cc
src/service_inspectors/cip/ips_cip_req.cc
src/service_inspectors/cip/ips_cip_rsp.cc
src/service_inspectors/cip/ips_cip_service.cc
src/service_inspectors/cip/ips_cip_status.cc
src/service_inspectors/dce_rpc/ips_dce_iface.cc
src/service_inspectors/dce_rpc/ips_dce_opnum.cc
src/service_inspectors/dce_rpc/ips_dce_stub_data.cc
src/service_inspectors/dnp3/ips_dnp3_data.cc
src/service_inspectors/dnp3/ips_dnp3_func.cc
src/service_inspectors/dnp3/ips_dnp3_ind.cc
src/service_inspectors/dnp3/ips_dnp3_obj.cc
src/service_inspectors/ftp_telnet/pp_ftp.cc
src/service_inspectors/gtp/ips_gtp_info.cc
src/service_inspectors/gtp/ips_gtp_type.cc
src/service_inspectors/gtp/ips_gtp_version.cc
src/service_inspectors/http2_inspect/http2_dummy_packet.h
src/service_inspectors/http_inspect/http_buffer_info.cc
src/service_inspectors/http_inspect/http_transaction.cc
src/service_inspectors/http_inspect/http_uri.cc
src/service_inspectors/http_inspect/ips_http.cc
src/service_inspectors/modbus/ips_modbus_data.cc
src/service_inspectors/modbus/ips_modbus_func.cc
src/service_inspectors/modbus/ips_modbus_unit.cc
src/service_inspectors/s7commplus/ips_s7comm_content.cc
src/service_inspectors/s7commplus/ips_s7comm_func.cc
src/service_inspectors/s7commplus/ips_s7comm_opcode.cc
src/service_inspectors/sip/ips_sip_method.cc
src/service_inspectors/sip/ips_sip_stat_code.cc
src/service_inspectors/sip/sip_utils.cc
src/service_inspectors/ssl/ips_ssl_state.cc
src/service_inspectors/ssl/ips_ssl_version.cc
src/stream/base/stream_base.cc
src/stream/base/stream_module.cc
src/stream/base/stream_module.h
src/stream/flush_bucket.cc
src/stream/flush_bucket.h
src/stream/tcp/ips_stream_reassemble.cc
src/stream/tcp/ips_stream_size.cc
src/utils/CMakeLists.txt
src/utils/memcap_allocator.h [new file with mode: 0644]
src/utils/sfmemcap.cc [deleted file]
src/utils/sfmemcap.h [deleted file]
src/utils/test/CMakeLists.txt
src/utils/test/memcap_allocator_test.cc [new file with mode: 0644]

index c8718aace74e34f262f6db167c242b629bfaf0f5..884ebe2ab3a58b0fb116f6c6b6bded2b86aa1f65 100644 (file)
@@ -37,7 +37,8 @@
 
 #include "filters/detection_filter.h"
 #include "framework/cursor.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_defs.h"
+#include "hash/hash_key_operations.h"
 #include "hash/xhash.h"
 #include "ips_options/extract.h"
 #include "ips_options/ips_flowbits.h"
@@ -79,93 +80,82 @@ struct detection_option_key_t
 static inline bool operator==(const struct timeval& a, const struct timeval& b)
 { return a.tv_sec == b.tv_sec && a.tv_usec == b.tv_usec; }
 
-static uint32_t detection_option_hash_func(HashFnc*, const unsigned char* k, int)
+class DetectionOptionHashKeyOps : public HashKeyOperations
 {
-    const detection_option_key_t* key = (const detection_option_key_t*)k;
+public:
+    DetectionOptionHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
 
-    if ( key->option_type != RULE_OPTION_TYPE_LEAF_NODE )
+    unsigned do_hash(const unsigned char* k, int) override
     {
-        IpsOption* opt = (IpsOption*)key->option_data;
-        return opt->hash();
+        const detection_option_key_t* key = (const detection_option_key_t*)k;
+
+        if ( key->option_type != RULE_OPTION_TYPE_LEAF_NODE )
+        {
+            IpsOption* opt = (IpsOption*)key->option_data;
+            return opt->hash();
+        }
+        return 0;
     }
-    return 0;
-}
 
-static bool detection_option_key_compare_func(const void* k1, const void* k2, size_t)
-{
-    const detection_option_key_t* key1 = (const detection_option_key_t*)k1;
-    const detection_option_key_t* key2 = (const detection_option_key_t*)k2;
+    bool key_compare(const void* k1, const void* k2, size_t) override
+    {
+        const detection_option_key_t* key1 = (const detection_option_key_t*)k1;
+        const detection_option_key_t* key2 = (const detection_option_key_t*)k2;
 
-    assert(key1 && key2);
+        assert(key1 && key2);
 
-    if ( key1->option_type != key2->option_type )
-        return false;
+        if ( key1->option_type != key2->option_type )
+            return false;
 
-    if ( key1->option_type != RULE_OPTION_TYPE_LEAF_NODE )
-    {
-        IpsOption* opt1 = (IpsOption*)key1->option_data;
-        IpsOption* opt2 = (IpsOption*)key2->option_data;
+        if ( key1->option_type != RULE_OPTION_TYPE_LEAF_NODE )
+        {
+            IpsOption* opt1 = (IpsOption*)key1->option_data;
+            IpsOption* opt2 = (IpsOption*)key2->option_data;
 
-        if ( *opt1 == *opt2 )
-            return true;
+            if ( *opt1 == *opt2 )
+                return true;
+        }
+        return false;
     }
-    return false;
-}
+};
 
-static int detection_hash_free_func(void* option_key, void*)
+class DetectionOptionHash : public XHash
 {
-    detection_option_key_t* key = (detection_option_key_t*)option_key;
+public:
 
-    if ( key->option_type != RULE_OPTION_TYPE_LEAF_NODE )
+    DetectionOptionHash(int rows, int key_len)
+        : XHash(rows, key_len)
     {
-        IpsOption* opt = (IpsOption*)key->option_data;
-        IpsManager::delete_option(opt);
+        initialize(new DetectionOptionHashKeyOps(nrows));
     }
-    return 0;
-}
-
-static XHash* DetectionHashTableNew()
-{
-    XHash* doht = new XHash(HASH_RULE_OPTIONS, sizeof(detection_option_key_t),
-        0, 0, false,  nullptr, detection_hash_free_func, true);
-
-    doht->set_key_opcodes(detection_option_hash_func, detection_option_key_compare_func);
-
-    return doht;
-}
-
-void DetectionHashTableFree(XHash* doht)
-{
-    delete doht;
-}
-
-void* add_detection_option(SnortConfig* sc, option_type_t type, void* option_data)
-{
-    if ( !sc->detection_option_hash_table )
-        sc->detection_option_hash_table = DetectionHashTableNew();
 
-    detection_option_key_t key;
-    key.option_type = type;
-    key.option_data = option_data;
+    ~DetectionOptionHash() override
+    {
+        delete_hash_table();
+    }
 
-    if ( void* p = sc->detection_option_hash_table->get_user_data(&key) )
-        return p;
+    void free_user_data(HashNode* hnode) override
+    {
+        detection_option_key_t* key = (detection_option_key_t*)hnode->key;
 
-    sc->detection_option_hash_table->insert(&key, option_data);
-    return nullptr;
-}
+        if ( key->option_type != RULE_OPTION_TYPE_LEAF_NODE )
+        {
+            IpsOption* opt = (IpsOption*)key->option_data;
+            IpsManager::delete_option(opt);
+        }
+    }
+};
 
 static uint32_t detection_option_tree_hash(detection_option_tree_node_t* node)
 {
-    uint32_t a,b,c;
-    int i;
-
-    if (!node)
-        return 0;
+    assert(node);
 
+    uint32_t a, b, c;
     a = b = c = 0;
 
-    for (i=0; i<node->num_children; i++)
+    for ( int i = 0; i < node->num_children; i++)
     {
 #if (defined(__ia64) || defined(__amd64) || defined(_LP64))
         {
@@ -198,19 +188,6 @@ static uint32_t detection_option_tree_hash(detection_option_tree_node_t* node)
     return c;
 }
 
-static uint32_t detection_option_tree_hash_func(HashFnc*, const unsigned char* k, int)
-{
-    const detection_option_key_t* key = (const detection_option_key_t*)k;
-    detection_option_tree_node_t* node;
-
-    if (!key || !key->option_data)
-        return 0;
-
-    node = (detection_option_tree_node_t*)key->option_data;
-
-    return detection_option_tree_hash(node);
-}
-
 static bool detection_option_tree_compare(
     const detection_option_tree_node_t* r, const detection_option_tree_node_t* l)
 {
@@ -232,40 +209,94 @@ static bool detection_option_tree_compare(
     return true;
 }
 
-static bool detection_option_tree_compare_func(const void* k1, const void* k2, size_t)
+void free_detection_option_tree(detection_option_tree_node_t* node)
+{
+    for (int i = 0; i < node->num_children; i++)
+        free_detection_option_tree(node->children[i]);
+
+    snort_free(node->children);
+    snort_free(node->state);
+    snort_free(node);
+}
+
+class DetectionOptionTreeHashKeyOps : public HashKeyOperations
 {
-    const detection_option_key_t* key_r = (const detection_option_key_t*)k1;
-    const detection_option_key_t* key_l = (const detection_option_key_t*)k2;
+public:
+    DetectionOptionTreeHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
 
-    if ( !key_r or !key_l )
-        return false;
+    unsigned do_hash(const unsigned char* k, int) override
+    {
+        assert(k);
+        const detection_option_key_t* key = (const detection_option_key_t*)k;
+        if ( !key->option_data )
+            return 0;
 
-    const detection_option_tree_node_t* r = (const detection_option_tree_node_t*)key_r->option_data;
-    const detection_option_tree_node_t* l = (const detection_option_tree_node_t*)key_l->option_data;
+        detection_option_tree_node_t* node = (detection_option_tree_node_t*)key->option_data;
 
-    return detection_option_tree_compare(r, l);
-}
+        return detection_option_tree_hash(node);
+    }
+
+    bool key_compare(const void* k1, const void* k2, size_t) override
+    {
+        assert(k1 && k2);
+
+        const detection_option_key_t* key_r = (const detection_option_key_t*)k1;
+        const detection_option_key_t* key_l = (const detection_option_key_t*)k2;
+
+        const detection_option_tree_node_t* r = (const detection_option_tree_node_t*)key_r->option_data;
+        const detection_option_tree_node_t* l = (const detection_option_tree_node_t*)key_l->option_data;
+
+        return detection_option_tree_compare(r, l);
+    }
+};
+
+class DetectionOptionTreeHash : public XHash
+{
+public:
+    DetectionOptionTreeHash(int rows, int key_len)
+        : XHash(rows, key_len)
+    {
+        initialize(new DetectionOptionTreeHashKeyOps(nrows));
+    }
+
+    ~DetectionOptionTreeHash() override
+    {
+        delete_hash_table();
+    }
 
-static int detection_option_tree_free_func(void*, void* data)
+    void free_user_data(HashNode* hnode) override
+    {
+        free_detection_option_tree((detection_option_tree_node_t*)hnode->data);
+    }
+
+};
+
+static DetectionOptionHash* DetectionHashTableNew()
 {
-    detection_option_tree_node_t* node = (detection_option_tree_node_t*)data;
-    free_detection_option_tree(node);
-    return 0;
+   return new DetectionOptionHash(HASH_RULE_OPTIONS, sizeof(detection_option_key_t));
 }
 
-void DetectionTreeHashTableFree(XHash* dtht)
+static DetectionOptionTreeHash* DetectionTreeHashTableNew()
 {
-    delete dtht;
+    return new DetectionOptionTreeHash(HASH_RULE_TREE, sizeof(detection_option_key_t));
 }
 
-static XHash* DetectionTreeHashTableNew()
+void* add_detection_option(SnortConfig* sc, option_type_t type, void* option_data)
 {
-    XHash* dtht = new XHash(HASH_RULE_TREE, sizeof(detection_option_key_t),
-        0, 0, false, nullptr, detection_option_tree_free_func, true);
+    if ( !sc->detection_option_hash_table )
+        sc->detection_option_hash_table = DetectionHashTableNew();
 
-    dtht->set_key_opcodes(detection_option_tree_hash_func, detection_option_tree_compare_func);
+    detection_option_key_t key;
+    key.option_type = type;
+    key.option_data = option_data;
+
+    if ( void* p = sc->detection_option_hash_table->get_user_data(&key) )
+        return p;
 
-    return dtht;
+    sc->detection_option_hash_table->insert(&key, option_data);
+    return nullptr;
 }
 
 void print_option_tree(detection_option_tree_node_t* node, int level)
@@ -527,7 +558,7 @@ int detection_option_node_evaluate(
 
         // Back up byte_extract vars so they don't get overwritten between rules
         trace_log(detection, TRACE_RULE_VARS, "Rule options variables: \n");
-        for ( int i = 0; i < NUM_IPS_OPTIONS_VARS; ++i )
+        for ( unsigned i = 0; i < NUM_IPS_OPTIONS_VARS; ++i )
         {
             GetVarValueByIndex(&(tmp_byte_extract_vars[i]), (int8_t)i);
             trace_logf_wo_name(detection, TRACE_RULE_VARS, "var[%d]=%d ", i,
@@ -552,7 +583,7 @@ int detection_option_node_evaluate(
                     detection_option_tree_node_t* child_node = node->children[i];
                     dot_node_state_t* child_state = child_node->state + get_instance_id();
 
-                    for ( int j = 0; j < NUM_IPS_OPTIONS_VARS; ++j )
+                    for ( unsigned j = 0; j < NUM_IPS_OPTIONS_VARS; ++j )
                         SetVarValueByIndex(tmp_byte_extract_vars[j], (int8_t)j);
 
                     if ( loop_count > 0 )
@@ -758,7 +789,7 @@ static void detection_option_node_update_otn_stats(detection_option_tree_node_t*
 
     if ( node->num_children )
     {
-        for ( int i=0; i < node->num_children; ++i )
+        for ( int i = 0; i < node->num_children; ++i )
             detection_option_node_update_otn_stats(node->children[i], &local_stats, checks,
                 timeouts, suspends);
     }
@@ -829,16 +860,3 @@ detection_option_tree_node_t* new_node(option_type_t type, void* data)
 
     return p;
 }
-
-void free_detection_option_tree(detection_option_tree_node_t* node)
-{
-    int i;
-    for (i=0; i<node->num_children; i++)
-    {
-        free_detection_option_tree(node->children[i]);
-    }
-    snort_free(node->children);
-    snort_free(node->state);
-    snort_free(node);
-}
-
index 6f6fdf4a98e4b4256a19a9e3b4b82262149924fb..f5523cfaaa1fbb9fa69f2d71683cc99b7b4d30dc 100644 (file)
 
 #include "detection/rule_option_types.h"
 #include "time/clock_defs.h"
-
 #include "main/snort_debug.h"
+
 extern Trace TRACE_NAME(detection);
 
 namespace snort
 {
+class HashNode;
+class XHash;
 struct Packet;
 struct SnortConfig;
-class XHash;
 }
 struct RuleLatencyState;
 
@@ -123,9 +124,6 @@ void* add_detection_option_tree(struct snort::SnortConfig*, detection_option_tre
 int detection_option_node_evaluate(
     detection_option_tree_node_t*, detection_option_eval_data_t&, const class Cursor&);
 
-void DetectionHashTableFree(snort::XHash*);
-void DetectionTreeHashTableFree(snort::XHash*);
-
 void print_option_tree(detection_option_tree_node_t*, int level);
 void detection_option_tree_update_otn_stats(snort::XHash*);
 
index 9f9fde9f0cb52352b7d153c7faf693547e46c39b..0d933ff0f3ab5958b25392b8155bd161d0d94b38 100644 (file)
@@ -37,6 +37,7 @@
 #include "framework/mpse.h"
 #include "framework/mpse_batch.h"
 #include "hash/ghash.h"
+#include "hash/xhash.h"
 #include "log/messages.h"
 #include "main/snort.h"
 #include "main/snort_config.h"
@@ -1660,8 +1661,8 @@ void fpDeleteFastPacketDetection(SnortConfig* sc)
         return;
 
     /* Cleanup the detection option tree */
-    DetectionHashTableFree(sc->detection_option_hash_table);
-    DetectionTreeHashTableFree(sc->detection_option_tree_hash_table);
+    delete sc->detection_option_hash_table;
+    delete sc->detection_option_tree_hash_table;
 
     fpFreeRuleMaps(sc);
     ServicePortGroupMapFree(sc->spgmmTable);
index bed991f8a9cf5632656e409504e6ddbde1119d26..5d6f8fb4a3bd82837eed37884d465f7805087118 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "signature.h"
 
+#include "hash/hash_defs.h"
 #include "hash/ghash.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
@@ -232,10 +233,10 @@ void OtnLookupAdd(GHash* otn_map, OptTreeNode* otn)
     key.sid = otn->sigInfo.sid;
 
     int status = otn_map->insert(&key, otn);
-    if ( status == GHASH_OK )
+    if ( status == HASH_OK )
         return;
 
-    assert(status == GHASH_INTABLE);
+    assert(status == HASH_INTABLE);
     ParseError("duplicate rule with same gid (%u) and sid (%u)", key.gid, key.sid);
 }
 
index afa2c3b0d80e3cca011cad4502572ce844746cd0..200d31b572f65e6830ce638dbefec198de50689b 100644 (file)
@@ -26,6 +26,7 @@
 #include "tag.h"
 
 #include "events/event.h"
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
@@ -102,11 +103,6 @@ struct TagNode
 };
 
 /*  G L O B A L S  **************************************************/
-static THREAD_LOCAL XHash* host_tag_cache_ptr = nullptr;
-
-// FIXIT-M utilize Flow instead of separate cache
-static THREAD_LOCAL XHash* ssn_tag_cache_ptr = nullptr;
-
 static THREAD_LOCAL uint32_t last_prune_time = 0;
 static THREAD_LOCAL uint32_t tag_alloc_faults = 0;
 static THREAD_LOCAL uint32_t tag_memory_usage = 0;
@@ -119,11 +115,10 @@ static THREAD_LOCAL unsigned s_sessions = 0;
 // (consecutive) sessions to be captured.
 static const unsigned s_max_sessions = 1;
 
+
 /*  P R O T O T Y P E S  ********************************************/
 static TagNode* TagAlloc(XHash*);
 static void TagFree(XHash*, TagNode*);
-static int TagFreeSessionNodeFunc(void* key, void* data);
-static int TagFreeHostNodeFunc(void* key, void* data);
 static int PruneTagCache(uint32_t, int);
 static int PruneTime(XHash* tree, uint32_t thetime);
 static void TagSession(Packet*, TagData*, uint32_t, uint16_t, void*);
@@ -131,6 +126,56 @@ static void TagHost(Packet*, TagData*, uint32_t, uint16_t, void*);
 static void AddTagNode(Packet*, TagData*, int, uint32_t, uint16_t, void*);
 static inline void SwapTag(TagNode*);
 
+class TagSessionCache : public XHash
+{
+public:
+    TagSessionCache(int rows, int key_len)
+        : XHash(rows, key_len)
+    {
+        initialize();
+        anr_enabled = false;
+        recycle_nodes = false;
+    }
+
+    ~TagSessionCache() override
+    {
+        delete_hash_table();
+    }
+
+    void free_user_data(HashNode* hnode) override
+    {
+        TagFree(this, (TagNode*)hnode->data);
+    }
+};
+
+class TagHostCache : public XHash
+{
+public:
+    TagHostCache(int rows, int key_len)
+        : XHash(rows, key_len)
+    {
+        initialize();
+        anr_enabled = false;
+        recycle_nodes = false;
+    }
+
+    ~TagHostCache() override
+    {
+        delete_hash_table();
+    }
+
+    void free_user_data(HashNode* hnode) override
+    {
+        TagFree(this, (TagNode*)hnode->data);
+    }
+};
+
+static THREAD_LOCAL TagHostCache* host_tag_cache = nullptr;
+
+// FIXIT-M utilize Flow instead of separate cache
+static THREAD_LOCAL TagSessionCache* ssn_tag_cache = nullptr;
+
+
 /**Calculated memory needed per node insertion into respective cache. Its includes
  * memory needed for allocating TagNode, HashNode and key size.
  *
@@ -141,9 +186,9 @@ static inline void SwapTag(TagNode*);
  */
 static inline unsigned int memory_per_node(XHash* hash)
 {
-    if ( hash == ssn_tag_cache_ptr )
+    if ( hash == ssn_tag_cache )
         return sizeof(tTagFlowKey) + sizeof(HashNode) + sizeof(TagNode);
-    else if ( hash == host_tag_cache_ptr )
+    else if ( hash == host_tag_cache )
         return sizeof(SfIp) + sizeof(HashNode) + sizeof(TagNode);
 
     return 0;
@@ -218,28 +263,6 @@ static void TagFree(
     tag_memory_usage -= memory_per_node(hash);
 }
 
-/**Callback from session tag cache to free user data.
- * @param key - pointer to key to session tag
- * @param data - pointer to user data, to be freed.
- * @returns 0
- */
-static int TagFreeSessionNodeFunc(void*, void* data)
-{
-    TagFree(ssn_tag_cache_ptr, (TagNode*)data);
-    return 0;
-}
-
-/**Callback from host tag cache to free user data.
- * @param key - pointer to key to session tag
- * @param data - pointer to user data, to be freed.
- * @returns 0
- */
-static int TagFreeHostNodeFunc(void*, void* data)
-{
-    TagFree(host_tag_cache_ptr, (TagNode*)data);
-    return 0;
-}
-
 /**
  * swap the sips and dips, dp's and sp's
  *
@@ -263,17 +286,14 @@ void InitTag()
 {
     unsigned int hashTableSize = TAG_MEMCAP/sizeof(TagNode);
 
-    ssn_tag_cache_ptr = new XHash(hashTableSize, sizeof(tTagFlowKey), 0, 0,
-        false, nullptr, TagFreeSessionNodeFunc, false);
-
-    host_tag_cache_ptr = new XHash(hashTableSize, sizeof(SfIp), 0, 0, false,
-        nullptr, TagFreeHostNodeFunc, false);
+    ssn_tag_cache = new TagSessionCache(hashTableSize, sizeof(tTagFlowKey));
+    host_tag_cache = new TagHostCache(hashTableSize, sizeof(SfIp));
 }
 
 void CleanupTag()
 {
-    delete ssn_tag_cache_ptr;
-    delete host_tag_cache_ptr;
+    delete ssn_tag_cache;
+    delete host_tag_cache;
 }
 
 static void TagSession(Packet* p, TagData* tag, uint32_t time, uint16_t event_id, void* log_list)
@@ -323,11 +343,11 @@ static void AddTagNode(Packet* p, TagData* tag, int mode, uint32_t now,
     }
     if (mode == TAG_SESSION)
     {
-        tag_cache_ptr = ssn_tag_cache_ptr;
+        tag_cache_ptr = ssn_tag_cache;
     }
     else
     {
-        tag_cache_ptr = host_tag_cache_ptr;
+        tag_cache_ptr = host_tag_cache;
     }
     idx = TagAlloc(tag_cache_ptr);
 
@@ -416,7 +436,7 @@ int CheckTagList(Packet* p, Event& event, void** log_list)
     char create_event = 1;
 
     /* check for active tags */
-    if (!host_tag_cache_ptr->get_node_count() && !ssn_tag_cache_ptr->get_node_count())
+    if (!host_tag_cache->get_num_nodes() && !ssn_tag_cache->get_num_nodes())
     {
         return 0;
     }
@@ -432,7 +452,7 @@ int CheckTagList(Packet* p, Event& event, void** log_list)
     idx.key.dp = p->ptrs.dp;
 
     /* check for session tags... */
-    returned = (TagNode*)ssn_tag_cache_ptr->get_user_data(&idx);
+    returned = (TagNode*)ssn_tag_cache->get_user_data(&idx);
 
     if (returned == nullptr)
     {
@@ -441,11 +461,11 @@ int CheckTagList(Packet* p, Event& event, void** log_list)
         idx.key.dp = p->ptrs.sp;
         idx.key.sp = p->ptrs.dp;
 
-        returned = (TagNode*)ssn_tag_cache_ptr->get_user_data(&idx);
+        returned = (TagNode*)ssn_tag_cache->get_user_data(&idx);
 
         if (returned == nullptr)
         {
-            returned = (TagNode*)host_tag_cache_ptr->get_user_data(&idx);
+            returned = (TagNode*)host_tag_cache->get_user_data(&idx);
 
             if (returned == nullptr)
             {
@@ -455,22 +475,22 @@ int CheckTagList(Packet* p, Event& event, void** log_list)
                 */
                 idx.key.sip = *p->ptrs.ip_api.get_src();
 
-                returned = (TagNode*)host_tag_cache_ptr->get_user_data(&idx);
+                returned = (TagNode*)host_tag_cache->get_user_data(&idx);
             }
 
             if (returned != nullptr)
             {
-                taglist = host_tag_cache_ptr;
+                taglist = host_tag_cache;
             }
         }
         else
         {
-            taglist = ssn_tag_cache_ptr;
+            taglist = ssn_tag_cache;
         }
     }
     else
     {
-        taglist = ssn_tag_cache_ptr;
+        taglist = ssn_tag_cache;
     }
 
     if (returned != nullptr)
@@ -533,7 +553,7 @@ int CheckTagList(Packet* p, Event& event, void** log_list)
 
         if ( !returned->metric )
         {
-            if (taglist->release_node(returned) != HASH_OK)
+            if (taglist->release_node(&returned->key) != HASH_OK)
             {
                 LogMessage("WARNING: failed to remove tagNode from hash.\n");
             }
@@ -558,35 +578,26 @@ static int PruneTagCache(uint32_t thetime, int mustdie)
 
     if (mustdie == 0)
     {
-        if (ssn_tag_cache_ptr->get_node_count() != 0)
-            pruned = PruneTime(ssn_tag_cache_ptr, thetime);
+        if (ssn_tag_cache->get_num_nodes() != 0)
+            pruned = PruneTime(ssn_tag_cache, thetime);
 
-        if (host_tag_cache_ptr->get_node_count() != 0)
-            pruned += PruneTime(host_tag_cache_ptr, thetime);
+        if (host_tag_cache->get_num_nodes() != 0)
+            pruned += PruneTime(host_tag_cache, thetime);
     }
     else
     {
         while (pruned < mustdie &&
-            (ssn_tag_cache_ptr->get_node_count() > 0 || host_tag_cache_ptr->get_node_count() > 0))
+            (ssn_tag_cache->get_num_nodes() > 0 || host_tag_cache->get_num_nodes() > 0))
         {
-            TagNode* lru_node;
+            if ( ssn_tag_cache->delete_lru_node() )
+                ++pruned;
+            else
+                LogMessage("WARNING: failed to remove tagNode from ssn hash.\n");
 
-            if ((lru_node = (TagNode*)ssn_tag_cache_ptr->get_lru_user_data()) != nullptr)
-            {
-                if (ssn_tag_cache_ptr->release_node(lru_node) != HASH_OK)
-                {
-                    LogMessage("WARNING: failed to remove tagNode from hash.\n");
-                }
-                pruned++;
-            }
-            if ((lru_node = (TagNode*)host_tag_cache_ptr->get_lru_user_data()) != nullptr)
-            {
-                if (host_tag_cache_ptr->release_node(lru_node) != HASH_OK)
-                {
-                    LogMessage("WARNING: failed to remove tagNode from hash.\n");
-                }
-                pruned++;
-            }
+            if ( host_tag_cache->delete_lru_node() )
+                ++pruned;
+            else
+                LogMessage("WARNING: failed to remove tagNode from host hash.\n");
         }
     }
 
@@ -602,7 +613,7 @@ static int PruneTime(XHash* tree, uint32_t thetime)
     {
         if ((lru_node->last_access + TAG_PRUNE_QUANTUM) < thetime)
         {
-            if (tree->release_node(lru_node) != HASH_OK)
+            if (tree->release_node(&lru_node->key) != HASH_OK)
             {
                 LogMessage("WARNING: failed to remove tagNode from hash.\n");
             }
index 1f435900a8bbab035e2c8ed871096a5182bacbe6..357e3874f74ff5a193ad7950461582c38af3e785 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "file_cache.h"
 
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
 
 using namespace snort;
 
-static int file_cache_anr_free_func(void*, void* data)
+class ExpectedFileCache : public XHash
 {
-    FileCache::FileNode* node = (FileCache::FileNode*)data;
+public:
+    ExpectedFileCache(unsigned rows, unsigned key_len, unsigned datasize)
+        : XHash(rows, key_len, datasize, 0)
+    { }
 
-    if (!node)
-        return 0;
-
-    struct timeval now;
-    packet_gettimeofday(&now);
+    ~ExpectedFileCache() override
+    {
+        delete_hash_table();
+    }
 
-    // only recycle expired nodes
-    if (timercmp(&node->cache_expire_time, &now, <))
+    bool is_node_recovery_ok(HashNode* hnode) override
     {
-        delete node->file;
-        return 0;
+        FileCache::FileNode* node = (FileCache::FileNode*)hnode->data;
+        if ( !node )
+            return true;
+
+        struct timeval now;
+        packet_gettimeofday(&now);
+        if ( timercmp(&node->cache_expire_time, &now, <) )
+           return true;
+        else
+            return false;
     }
-    else
-        return 1;
-}
 
-static int file_cache_free_func(void*, void* data)
-{
-    FileCache::FileNode* node = (FileCache::FileNode*)data;
-    if (node)
+    void free_user_data(HashNode* hnode) override
     {
-        delete node->file;
+        FileCache::FileNode* node = (FileCache::FileNode*)hnode->data;
+        if ( node )
+            delete node->file;
     }
-    return 0;
-}
+};
 
 // Return the time in ms since we started waiting for pending file lookup.
 static int64_t time_elapsed_ms(struct timeval* now, struct timeval* expire_time, int64_t lookup_timeout)
@@ -79,8 +84,7 @@ static int64_t time_elapsed_ms(struct timeval* now, struct timeval* expire_time,
 FileCache::FileCache(int64_t max_files_cached)
 {
     max_files = max_files_cached;
-    fileHash = new XHash(max_files, sizeof(FileHashKey), sizeof(FileNode),
-        0, true, file_cache_anr_free_func, file_cache_free_func, true);
+    fileHash = new ExpectedFileCache(max_files, sizeof(FileHashKey), sizeof(FileNode));
     fileHash->set_max_nodes(max_files);
 }
 
@@ -155,18 +159,15 @@ FileContext* FileCache::find(const FileHashKey& hashKey, int64_t timeout)
 {
     std::lock_guard<std::mutex> lock(cache_mutex);
 
-    if (!fileHash->get_node_count())
-    {
+    if ( !fileHash->get_num_nodes() )
         return nullptr;
-    }
 
     HashNode* hash_node = fileHash->find_node(&hashKey);
-
-    if (!hash_node)
+    if ( !hash_node )
         return nullptr;
 
     FileNode* node = (FileNode*)hash_node->data;
-    if (!node)
+    if ( !node )
     {
         fileHash->release_node(hash_node);
         return nullptr;
@@ -175,7 +176,7 @@ FileContext* FileCache::find(const FileHashKey& hashKey, int64_t timeout)
     struct timeval now;
     packet_gettimeofday(&now);
 
-    if (timercmp(&node->cache_expire_time, &now, <))
+    if ( timercmp(&node->cache_expire_time, &now, <) )
     {
         fileHash->release_node(hash_node);
         return nullptr;
index 1ee25d89dc4705292d99d00b54a52f8a0d2b84d4..4c56cf10d1c8699501769b11c8cd88c2c22e8958 100644 (file)
 
 #include "file_config.h"
 
-namespace snort
-{
-class XHash;
-}
+class ExpectedFileCache;
 
 class FileCache
 {
@@ -74,7 +71,7 @@ private:
     int store_verdict(snort::Flow*, snort::FileInfo*, int64_t timeout);
 
     /* The hash table of expected files */
-    snort::XHash* fileHash = nullptr;
+    ExpectedFileCache* fileHash = nullptr;
     int64_t block_timeout = DEFAULT_FILE_BLOCK_TIMEOUT;
     int64_t lookup_timeout = DEFAULT_FILE_LOOKUP_TIMEOUT;
     int64_t max_files = DEFAULT_MAX_FILES_CACHED;
index 2e7143ff51f2020baa84b39d133a7dc5cf32d4bf..5796f101b32fc7cc0619b8dbfff9ab651ad88c1a 100644 (file)
@@ -32,6 +32,7 @@
 #include <algorithm>
 #include <cassert>
 
+#include "hash/ghash.h"
 #include "log/messages.h"
 #include "utils/util.h"
 
index c698db9915dffb25f56798943e8d96c4010377e6..81c621ae3113899e1bc5e0ef661a2bfd9bfd97e4 100644 (file)
 #include <list>
 #include <vector>
 
-#include "hash/ghash.h"
-
 #include "file_lib.h"
 
+namespace snort
+{
+class GHash;
+}
+
 #define MAX_BRANCH (UINT8_MAX + 1)
 
 enum IdNodeState
index 4819c388d0f1618f88dc27b891cd86cdeddd1e97..58be9bf45439db3f1d22166ebc48bdbb615aabcc 100644 (file)
@@ -290,7 +290,7 @@ bool FileIdModule::set(const char*, Value& v, SnortConfig*)
         {
             if (Snort::is_reloading() && !FileService::is_file_capture_enabled())
             {
-                ReloadError("Enabling file capture requires a restart\n");
+                ReloadError("Enabling file_id.enable_capture requires a restart\n");
                 return false;
             }
             fp.set_file_capture(true);
@@ -388,7 +388,7 @@ bool FileIdModule::set(const char*, Value& v, SnortConfig*)
         if (file_rule.use.capture_enabled && Snort::is_reloading()
             && !FileService::is_file_capture_enabled())
         {
-            ReloadError("Enabling file capture requires a restart\n");
+            ReloadError("Enabling file_id.enable_file_capture requires a restart\n");
             return false;
         }
     }
index d8a53a57aef2758243e741260ebf441696935c1c..7aaaf7bdd6ba4ee3d1c9166c768b670d7ee1e825 100644 (file)
@@ -87,14 +87,14 @@ void FileService::verify_reload(SnortConfig* sc)
         return;
 
     if (max_files_cached != conf->max_files_cached)
-        ReloadError("Changing file_id:max_files_cached requires a restart\n");
+        ReloadError("Changing file_id.max_files_cached requires a restart\n");
 
     if (file_capture_enabled)
     {
         if (capture_memcap != conf->capture_memcap)
-            ReloadError("Changing file_id:capture_memcap requires a restart\n");
+            ReloadError("Changing file_id.capture_memcap requires a restart\n");
         if (capture_block_size != conf->capture_block_size)
-            ReloadError("Changing file_id:capture_block_size requires a restart\n");
+            ReloadError("Changing file_id.capture_block_size requires a restart\n");
     }
 }
 
index a985f6caeec3322b1bfd4afbf7a9aad50e9f73d6..6e47a7ef50157c25550254b87f546f70e132e89d 100644 (file)
@@ -29,6 +29,7 @@
 #include "main/thread.h"
 #include "detection/rules.h"
 #include "hash/ghash.h"
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "sfip/sf_ip.h"
 #include "sfip/sf_ipvar.h"
@@ -146,14 +147,12 @@ static void SFRF_New(unsigned nbytes)
 
     /* Calc max ip nodes for this memory */
     if ( nbytes < SFRF_BYTES )
-    {
         nbytes = SFRF_BYTES;
-    }
+
     nrows = nbytes / (SFRF_BYTES);
 
     /* Create global hash table for all of the IP Nodes */
-    rf_hash = new XHash(nrows, sizeof(tSFRFTrackingNodeKey),
-        sizeof(tSFRFTrackingNode), nbytes, true, nullptr, nullptr, true);
+    rf_hash = new XHash(nrows, sizeof(tSFRFTrackingNodeKey), sizeof(tSFRFTrackingNode), nbytes);
 }
 
 void SFRF_Delete()
@@ -168,7 +167,7 @@ void SFRF_Delete()
 void SFRF_Flush()
 {
     if ( rf_hash )
-        rf_hash->clear();
+        rf_hash->clear_hash();
 }
 
 static void SFRF_ConfigNodeFree(void* item)
@@ -782,30 +781,24 @@ static tSFRFTrackingNode* _getSFRFTrackingNode(const SfIp* ip, unsigned tid, tim
     key.policyId = get_ips_policy()->policy_id;
     key.padding = 0;
 
-    /*
-     * Check for any Permanent sid objects for this gid or add this one ...
-     */
-    HashNode* hnode = rf_hash->get_node((void*)&key);
-    if ( !hnode )
+    // Check for any Permanent sid objects for this gid or add this one ...
+    if ( rf_hash->insert(&key, nullptr) == HASH_NOMEM )
     {
         // xhash_get_node fails to insert only if rf_hash is full.
         rate_filter_stats.xhash_nomem_peg++;
         return dynNode;
     }
 
-    if ( hnode->data )
+    dynNode = (tSFRFTrackingNode*)rf_hash->get_user_data();
+    if ( dynNode->filterState == FS_NEW )
     {
-        dynNode = (tSFRFTrackingNode*)hnode->data;
-
-        if ( dynNode->filterState == FS_NEW )
-        {
-            // first time initialization
-            dynNode->tstart = curTime;
+        // first time initialization
+        dynNode->tstart = curTime;
 #ifdef SFRF_OVER_RATE
-            dynNode->tlast = curTime;
+        dynNode->tlast = curTime;
 #endif
-            dynNode->filterState = FS_OFF;
-        }
+        dynNode->filterState = FS_OFF;
     }
+
     return dynNode;
 }
index b83ba0fa5920855a1bc5fb170d4be4fb5d542e56..6eaaa5d2d4cefedf85da4fe89b63dc385db524e3 100644 (file)
@@ -36,6 +36,7 @@
 #include <cassert>
 
 #include "hash/ghash.h"
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "main/thread.h"
 #include "sfip/sf_ipvar.h"
@@ -60,7 +61,7 @@ XHash* sfthd_new_hash(unsigned nbytes, size_t key, size_t data)
         nbytes = size;
     nrows = nbytes / size;
 
-    return new XHash(nrows, key, data, nbytes, true, nullptr, nullptr, true);
+    return new XHash(nrows, key, data, nbytes);
 }
 
 /*!
@@ -891,7 +892,7 @@ int sfthd_test_local(
     if (status == HASH_INTABLE)
     {
         /* Already in the table */
-        sfthd_ip_node = (THD_IP_NODE*)local_hash->get_cnode()->data;
+        sfthd_ip_node = (THD_IP_NODE*)local_hash->get_user_data();
 
         /* Increment the event count */
         sfthd_ip_node->count++;
@@ -989,7 +990,7 @@ static inline int sfthd_test_global(
     if (status == HASH_INTABLE)
     {
         /* Already in the table */
-        sfthd_ip_node = (THD_IP_NODE*)global_hash->get_cnode()->data;
+        sfthd_ip_node = (THD_IP_NODE*)global_hash->get_user_data();
 
         /* Increment the event count */
         sfthd_ip_node->count++;
index 69873cc46976d928b7f258df6a638197f36c20dd..d63b6c6a4b5f69ce91db54bcf93a0d94ea857341 100644 (file)
@@ -134,7 +134,7 @@ void ExpectCache::prune()
 
     for (unsigned i = 0; i < MAX_PRUNE; ++i )
     {
-        ExpectNode* node = (ExpectNode*)hash_table->first();
+        ExpectNode* node = (ExpectNode*)hash_table->lru_first();
 
         if ( !node || now <= node->expires )
             break;
@@ -147,7 +147,7 @@ void ExpectCache::prune()
 
 ExpectNode* ExpectCache::find_node_by_packet(Packet* p, FlowKey &key)
 {
-    if (!hash_table->get_count())
+    if (!hash_table->get_num_nodes())
         return nullptr;
 
     const SfIp* srcIP = p->ptrs.ip_api.get_src();
@@ -171,7 +171,7 @@ ExpectNode* ExpectCache::find_node_by_packet(Packet* p, FlowKey &key)
     */
     // FIXIT-P X This should be optimized to only do full matches when full keys
     //      are present, likewise for partial keys.
-    ExpectNode* node = (ExpectNode*) hash_table->find(&key);
+    ExpectNode* node = (ExpectNode*) hash_table->get_user_data(&key);
     if (!node)
     {
         // FIXIT-M X This logic could fail if IPs were equal because the original key
@@ -192,12 +192,12 @@ ExpectNode* ExpectCache::find_node_by_packet(Packet* p, FlowKey &key)
             port2 = key.port_h;
             key.port_h = 0;
         }
-        node = (ExpectNode*) hash_table->find(&key);
+        node = (ExpectNode*) hash_table->get_user_data(&key);
         if (!node)
         {
             key.port_l = port1;
             key.port_h = port2;
-            node = (ExpectNode*) hash_table->find(&key);
+            node = (ExpectNode*) hash_table->get_user_data(&key);
             if (!node)
                 return nullptr;
         }
@@ -206,7 +206,7 @@ ExpectNode* ExpectCache::find_node_by_packet(Packet* p, FlowKey &key)
     {
         if (node->head)
             node->clear(free_list);
-        hash_table->release(&key);
+        hash_table->release_node(&key);
         return nullptr;
     }
     /* Make sure the packet direction is correct */
@@ -257,7 +257,7 @@ bool ExpectCache::process_expected(ExpectNode* node, FlowKey& key, Packet* p, Fl
         lws->ssn_state.snort_protocol_id = node->snort_protocol_id;
 
     if (!node->count)
-        hash_table->release(&key);
+        hash_table->release_node(&key);
 
     return ignoring;
 }
@@ -270,11 +270,9 @@ ExpectCache::ExpectCache(uint32_t max)
 {
     // -size forces use of abs(size) ie w/o bumping up
     hash_table = new ZHash(-MAX_HASH, sizeof(FlowKey));
-    hash_table->set_key_opcodes(FlowKey::hash, FlowKey::is_equal);
-
     nodes = new ExpectNode[max];
     for (unsigned i = 0; i < max; ++i)
-        hash_table->push(nodes+i);
+        hash_table->push(nodes + i);
 
     /* Preallocate a pool of ExpectFlows big enough to handle the worst case
         requirement (max number of nodes * max flows per node) and add them all
@@ -332,54 +330,44 @@ int ExpectCache::add_flow(const Packet *ctrlPkt, PktType type, IpProtocol ip_pro
     uint16_t vlanId = (ctrlPkt->proto_bits & PROTO_BIT__VLAN) ? layer::get_vlan_layer(ctrlPkt)->vid() : 0;
     uint32_t mplsId = (ctrlPkt->proto_bits & PROTO_BIT__MPLS) ? ctrlPkt->ptrs.mplsHdr.label : 0;
     uint16_t addressSpaceId = ctrlPkt->pkth->address_space_id;
-
     FlowKey key;
     bool reversed_key = key.init(type, ip_proto, cliIP, cliPort, srvIP, srvPort,
             vlanId, mplsId, addressSpaceId);
 
     bool new_node = false;
-    ExpectNode* node = (ExpectNode*) hash_table->get(&key, &new_node);
-    if (!node)
+    ExpectNode* node = (ExpectNode*) hash_table->get_user_data(&key);
+    if ( !node )
     {
         prune();
-        node = (ExpectNode*) hash_table->get(&key, &new_node);
-        /* The flow free list should never be empty if there was a node
-            to be (re-)used unless we managed to leak some.  Check just
-            in case.  Maybe assert instead? */
-        if (!node || !free_list)
-        {
-            ++overflows;
-            return -1;
-        }
+        node = (ExpectNode*) hash_table->get(&key);
+        assert(node);
+        new_node = true;
     }
-
-    /* If the node is past its expiration date, whack it and reuse it. */
-    if (!new_node && packet_time() > node->expires)
+    else if ( packet_time() > node->expires )
     {
+        // node is past its expiration date, whack it and reuse it.
         node->clear(free_list);
         new_node = true;
     }
 
     ExpectFlow* last = nullptr;
-    if (!new_node)
+    if ( !new_node )
     {
-        // Requests will be rejected if the snort_protocol_id doesn't
-        // match what has already been set.
-        if (node->snort_protocol_id != snort_protocol_id)
+        //  reject if the snort_protocol_id doesn't match
+        if ( node->snort_protocol_id != snort_protocol_id )
         {
-            if (node->snort_protocol_id && snort_protocol_id)
+            if ( node->snort_protocol_id && snort_protocol_id )
                 return -1;
             node->snort_protocol_id = snort_protocol_id;
         }
 
         last = node->tail;
-        if (last)
+        if ( last )
         {
             FlowData* lfd = last->data;
-
-            while (lfd)
+            while ( lfd )
             {
-                if (lfd->get_id() == fd->get_id())
+                if ( lfd->get_id() == fd->get_id() )
                 {
                     last = nullptr;
                     break;
@@ -403,9 +391,9 @@ int ExpectCache::add_flow(const Packet *ctrlPkt, PktType type, IpProtocol ip_pro
     }
 
     bool new_expect_flow = false;
-    if (!last)
+    if ( !last )
     {
-        if (node->count >= MAX_LIST)
+        if ( node->count >= MAX_LIST )
         {
             // fail when maxed out
             ++overflows;
@@ -414,7 +402,7 @@ int ExpectCache::add_flow(const Packet *ctrlPkt, PktType type, IpProtocol ip_pro
         last = free_list;
         free_list = free_list->next;
 
-        if (!node->tail)
+        if ( !node->tail )
             node->head = last;
         else
             node->tail->next = last;
@@ -427,7 +415,7 @@ int ExpectCache::add_flow(const Packet *ctrlPkt, PktType type, IpProtocol ip_pro
     last->add_flow_data(fd);
     node->expires = packet_time() + MAX_WAIT;
     ++expects;
-    if (new_expect_flow)
+    if ( new_expect_flow )
     {
         // chain all expected flows created by this packet
         packet_expect_flows->emplace_back(last);
index b7ef59dc913ca76faa20f93f45922bee64d4c0da..8b33945315c08c4a7d9e6958fd41a921e5324170 100644 (file)
@@ -53,11 +53,8 @@ static const unsigned ALL_FLOWS = 3;
 FlowCache::FlowCache(const FlowCacheConfig& cfg) : config(cfg)
 {
     hash_table = new ZHash(config.max_flows, sizeof(FlowKey));
-    hash_table->set_key_opcodes(FlowKey::hash, FlowKey::is_equal);
-
     uni_flows = new FlowUniList;
     uni_ip_flows = new FlowUniList;
-
     flags = 0x0;
 
     assert(prune_stats.get_total() == 0);
@@ -79,12 +76,12 @@ void FlowCache::push(Flow* flow)
 
 unsigned FlowCache::get_count()
 {
-    return hash_table ? hash_table->get_count() : 0;
+    return hash_table ? hash_table->get_num_nodes() : 0;
 }
 
 Flow* FlowCache::find(const FlowKey* key)
 {
-    Flow* flow = (Flow*)hash_table->find(key);
+    Flow* flow = (Flow*)hash_table->get_user_data(key);
 
     if ( flow )
     {
@@ -119,7 +116,6 @@ Flow* FlowCache::allocate(const FlowKey* key)
 {
     time_t timestamp = packet_time();
     Flow* flow = (Flow*)hash_table->get(key);
-
     if ( !flow )
     {
         if ( flows_allocated < config.max_flows )
@@ -160,7 +156,7 @@ void FlowCache::remove(Flow* flow)
     // FIXIT-M This check is added for offload case where both Flow::reset
     // and Flow::retire try remove the flow from hash. Flow::reset should
     // just mark the flow as pending instead of trying to remove it.
-    if ( hash_table->release(flow->key) )
+    if ( !hash_table->release_node(flow->key) )
         memory::MemoryCap::update_deallocations(config.proto[to_utype(flow->key->pkt_type)].cap_weight);
 }
 
@@ -184,7 +180,7 @@ unsigned FlowCache::prune_stale(uint32_t thetime, const Flow* save_me)
     ActiveSuspendContext act_susp;
 
     unsigned pruned = 0;
-    auto flow = static_cast<Flow*>(hash_table->first());
+    auto flow = static_cast<Flow*>(hash_table->lru_first());
 
     while ( flow and pruned <= cleanup_flows )
     {
@@ -196,7 +192,7 @@ unsigned FlowCache::prune_stale(uint32_t thetime, const Flow* save_me)
             if ( hash_table->get_count() == 1 )
                 break;
 
-            hash_table->touch();
+            hash_table->lru_touch();
         }
 #else
         // Reached the current flow. This *should* be the newest flow
@@ -213,7 +209,7 @@ unsigned FlowCache::prune_stale(uint32_t thetime, const Flow* save_me)
         release(flow, PruneReason::IDLE);
         ++pruned;
 
-        flow = static_cast<Flow*>(hash_table->first());
+        flow = static_cast<Flow*>(hash_table->lru_first());
     }
 
     return pruned;
@@ -262,11 +258,11 @@ unsigned FlowCache::prune_excess(const Flow* save_me)
 
     // initially skip offloads but if that doesn't work the hash table is iterated from the
     // beginning again. prune offloads at that point.
-    unsigned ignore_offloads = hash_table->get_count();
+    unsigned ignore_offloads = hash_table->get_num_nodes();
 
-    while ( hash_table->get_count() > max_cap and hash_table->get_count() > blocks )
+    while ( hash_table->get_num_nodes() > max_cap and hash_table->get_num_nodes() > blocks )
     {
-        auto flow = static_cast<Flow*>(hash_table->first());
+        auto flow = static_cast<Flow*>(hash_table->lru_first());
         assert(flow); // holds true because hash_table->get_count() > 0
 
         if ( (save_me and flow == save_me) or flow->was_blocked() or
@@ -279,8 +275,7 @@ unsigned FlowCache::prune_excess(const Flow* save_me)
 
             // FIXIT-M we should update last_data_seen upon touch to ensure
             // the hash_table LRU list remains sorted by time
-            if ( !hash_table->touch() )
-                break;
+            hash_table->lru_touch();
         }
         else
         {
@@ -292,7 +287,7 @@ unsigned FlowCache::prune_excess(const Flow* save_me)
             --ignore_offloads;
     }
 
-    if (!pruned and hash_table->get_count() > max_cap)
+    if (!pruned and hash_table->get_num_nodes() > max_cap)
     {
         prune_one(PruneReason::EXCESS, true);
         ++pruned;
@@ -304,11 +299,11 @@ unsigned FlowCache::prune_excess(const Flow* save_me)
 bool FlowCache::prune_one(PruneReason reason, bool do_cleanup)
 {
     // so we don't prune the current flow (assume current == MRU)
-    if ( hash_table->get_count() <= 1 )
+    if ( hash_table->get_num_nodes() <= 1 )
         return false;
 
     // ZHash returns in LRU order, which is updated per packet via find --> move_to_front call
-    auto flow = static_cast<Flow*>(hash_table->first());
+    auto flow = static_cast<Flow*>(hash_table->lru_first());
     assert(flow);
 
     flow->ssn_state.session_flags |= SSNFLAG_PRUNED;
@@ -322,10 +317,10 @@ unsigned FlowCache::timeout(unsigned num_flows, time_t thetime)
     ActiveSuspendContext act_susp;
     unsigned retired = 0;
 
-    auto flow = static_cast<Flow*>(hash_table->current());
+    auto flow = static_cast<Flow*>(hash_table->lru_current());
 
     if ( !flow )
-        flow = static_cast<Flow*>(hash_table->first());
+        flow = static_cast<Flow*>(hash_table->lru_first());
 
     while ( flow and (retired < num_flows) )
     {
@@ -340,7 +335,7 @@ unsigned FlowCache::timeout(unsigned num_flows, time_t thetime)
         if ( HighAvailabilityManager::in_standby(flow) or
             flow->is_suspended() )
         {
-            flow = static_cast<Flow*>(hash_table->next());
+            flow = static_cast<Flow*>(hash_table->lru_next());
             continue;
         }
 
@@ -349,7 +344,7 @@ unsigned FlowCache::timeout(unsigned num_flows, time_t thetime)
 
         ++retired;
 
-        flow = static_cast<Flow*>(hash_table->current());
+        flow = static_cast<Flow*>(hash_table->lru_current());
     }
 
     return retired;
@@ -357,22 +352,20 @@ unsigned FlowCache::timeout(unsigned num_flows, time_t thetime)
 
 unsigned FlowCache::delete_active_flows(unsigned mode, unsigned num_to_delete, unsigned &deleted)
 {
-    unsigned flows_to_check = hash_table->get_count();
+    unsigned flows_to_check = hash_table->get_num_nodes();
     while ( num_to_delete && flows_to_check-- )
     {
-        auto flow = static_cast<Flow*>(hash_table->first());
+        auto flow = static_cast<Flow*>(hash_table->lru_first());
         assert(flow);
         if ( (mode == ALLOWED_FLOWS_ONLY and (flow->was_blocked() || flow->is_suspended()))
             or (mode == OFFLOADED_FLOWS_TOO and flow->was_blocked()) )
         {
-            if ( !hash_table->touch() )
-                break;
-
+            hash_table->lru_touch();
             continue;
         }
 
         // we have a winner...
-        hash_table->remove(flow->key);
+        hash_table->remove();
         if ( flow->next )
             unlink_uni(flow);
 
@@ -427,7 +420,7 @@ unsigned FlowCache::purge()
 
     unsigned retired = 0;
 
-    while ( auto flow = static_cast<Flow*>(hash_table->first()) )
+    while ( auto flow = static_cast<Flow*>(hash_table->lru_first()) )
     {
         retire(flow);
         ++retired;
index 72575eb1d6edba0f30bc14d314debb81effcd96a..b0c10fa875cfca720c9255060d8c9f0ce9ff7dbf 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "flow/flow_key.h"
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "main/snort_config.h"
 #include "protocols/icmp4.h"
 #include "protocols/icmp6.h"
@@ -297,46 +297,10 @@ bool FlowKey::init(
 // hash foo
 //-------------------------------------------------------------------------
 
-uint32_t FlowKey::hash(HashFnc* hf, const unsigned char* p, int)
-{
-    uint32_t a, b, c;
-    a = b = c = hf->hardener;
-
-    const uint32_t* d = (const uint32_t*)p;
-
-    a += d[0];   // IPv6 lo[0]
-    b += d[1];   // IPv6 lo[1]
-    c += d[2];   // IPv6 lo[2]
-
-    mix(a, b, c);
-
-    a += d[3];   // IPv6 lo[3]
-    b += d[4];   // IPv6 hi[0]
-    c += d[5];   // IPv6 hi[1]
-
-    mix(a, b, c);
-
-    a += d[6];   // IPv6 hi[2]
-    b += d[7];   // IPv6 hi[3]
-    c += d[8];   // mpls label
-
-    mix(a, b, c);
-
-    a += d[9];   // port lo & port hi
-    b += d[10];  // vlan tag, address space id
-    c += d[11];  // ip_proto, pkt_type, version, and 8 bits of zeroed pad
-
-    finalize(a, b, c);
-
-    return c;
-}
-
 bool FlowKey::is_equal(const void* s1, const void* s2, size_t)
 {
-    const uint64_t* a,* b;
-
-    a = (const uint64_t*)s1;
-    b = (const uint64_t*)s2;
+    const uint64_t* a = (const uint64_t*)s1;
+    const uint64_t* b = (const uint64_t*)s2;
     if (*a - *b)
         return false;               /* Compares IPv4 lo/hi
                                    Compares IPv6 low[0,1] */
@@ -370,3 +334,43 @@ bool FlowKey::is_equal(const void* s1, const void* s2, size_t)
     return true;
 }
 
+unsigned FlowHashKeyOps::do_hash(const unsigned char* k, int)
+{
+    uint32_t a, b, c;
+    a = b = c = hardener;
+
+    const uint32_t* d = (const uint32_t*)k;
+
+    a += d[0];   // IPv6 lo[0]
+    b += d[1];   // IPv6 lo[1]
+    c += d[2];   // IPv6 lo[2]
+
+    mix(a, b, c);
+
+    a += d[3];   // IPv6 lo[3]
+    b += d[4];   // IPv6 hi[0]
+    c += d[5];   // IPv6 hi[1]
+
+    mix(a, b, c);
+
+    a += d[6];   // IPv6 hi[2]
+    b += d[7];   // IPv6 hi[3]
+    c += d[8];   // mpls label
+
+    mix(a, b, c);
+
+    a += d[9];   // port lo & port hi
+    b += d[10];  // vlan tag, address space id
+    c += d[11];  // ip_proto, pkt_type, version, and 8 bits of zeroed pad
+
+    finalize(a, b, c);
+
+    return c;
+}
+
+bool FlowHashKeyOps::key_compare(const void* k1, const void* k2, size_t len)
+{
+    return FlowKey::is_equal(k1, k2, len);
+}
+
+
index 4d9fb4ad88855018cd9335c9a1455845f0fa5366..c85129dc0621b65854a6a480abac26e55c449eee 100644 (file)
 #include <cstdint>
 
 #include "framework/decode_data.h"
+#include "hash/hash_key_operations.h"
 #include "utils/cpp_macros.h"
 
-struct HashFnc;
+class HashKeyOperations;
 
 namespace snort
 {
 struct SfIp;
 
+class FlowHashKeyOps : public HashKeyOperations
+{
+public:
+    FlowHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
+
+    unsigned do_hash(const unsigned char* k, int len) override;
+    bool key_compare(const void* k1, const void* k2, size_t) override;
+};
+
+
 PADDING_GUARD_BEGIN
 struct SO_PUBLIC FlowKey
 {
@@ -70,8 +83,7 @@ struct SO_PUBLIC FlowKey
     void init_address_space(uint16_t);
 
     // If this data structure changes size, compare must be updated!
-    static uint32_t hash(HashFnc*, const unsigned char* d, int);
-    static bool is_equal(const void* s1, const void* s2, size_t);
+    static bool is_equal(const void* k1, const void* k2, size_t);
 
 private:
     bool init4(
index 2cb88afba348be460b746912b682ea66d4ccad90..df99e24f79e3a6dbc11f343f3151ba9269b0867c 100644 (file)
@@ -13,9 +13,11 @@ add_cpputest( flow_cache_test
         ../flow_cache.cc
         ../flow_control.cc
         ../flow_key.cc
-        ../../hash/zhash.cc
-        ../../hash/hashfcn.cc
+        ../../hash/hash_key_operations.cc
+        ../../hash/hash_lru_cache.cc
         ../../hash/primetable.cc
+        ../../hash/xhash.cc
+        ../../hash/zhash.cc
 )
 
 add_cpputest( session_test )
index 44f0763ff9db50fd7cdbb48eff038e4e84706c87..7f6fc3ec531487e0775e0c5f5020c02b27bf46e7 100644 (file)
@@ -25,7 +25,7 @@
 
 #include <cstring>
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 
 using namespace snort;
 
index 8cbdd87e27278ab6aac1d447da639af7296aa5ed..029a77ef9a9e5e7e4ea5be2ea6c3b3c0d8aefbe8 100644 (file)
@@ -1,23 +1,25 @@
 
 set (HASH_INCLUDES
+    ghash.h
     hashes.h
     hash_defs.h
-    ghash.h 
-    xhash.h 
-    hashfcn.h
+    hash_key_operations.h
     lru_cache_shared.h
+    xhash.h
 )
 
 add_library( hash OBJECT
     ${HASH_INCLUDES}
+    ghash.cc
     hashes.cc
+    hash_lru_cache.cc
+    hash_lru_cache.h
+    hash_key_operations.cc
     lru_cache_shared.cc
-    ghash.cc 
-    hashfcn.cc 
-    primetable.cc 
-    primetable.h 
-    xhash.cc 
-    zhash.cc 
+    primetable.cc
+    primetable.h
+    xhash.cc
+    zhash.cc
     zhash.h
 )
 
index 80e264bb4a0c885bb0d6e465a57dbd0c3bdd056f..a9e20a8d8a9aaf7b6c3a1c9b12d692070f7e47aa 100644 (file)
@@ -62,6 +62,7 @@
 
 #include "utils/util.h"
 
+#include "hash_defs.h"
 #include "primetable.h"
 
 namespace snort
@@ -75,7 +76,7 @@ GHash::GHash(int nrows_, unsigned keysize, bool userkey, gHashFree userfree)
     else
         nrows = -nrows_;
 
-    hashfcn = hashfcn_new(nrows);
+    hashfcn = new HashKeyOperations(nrows);
     table = (GHashNode**)snort_calloc(nrows, sizeof(GHashNode*));
     for ( int i = 0; i < nrows; i++ )
         table[i] = nullptr;
@@ -87,8 +88,6 @@ GHash::GHash(int nrows_, unsigned keysize, bool userkey, gHashFree userfree)
 
 GHash::~GHash()
 {
-    hashfcn_free(hashfcn);
-
     for (int i = 0; i < nrows; i++)
         for ( GHashNode* node = table[i]; node; )
         {
@@ -105,22 +104,13 @@ GHash::~GHash()
         }
 
     snort_free(table);
+    delete hashfcn;
 }
 
-// set key length, hashkey, and index parameters required to find/add/remove a node
-// the parameters set are valid until for the life of the initial method called
-void GHash::set_node_parameters(const void* const key)
-{
-    klen = ( keysize > 0  ) ? keysize : strlen((const char*)key) + 1;
-    hashkey = hashfcn->hash_fcn(hashfcn, (const unsigned char*)key, klen);
-    index = hashkey % nrows;
-}
-
-GHashNode* GHash::find_node(const void* const key)
+GHashNode* GHash::find_node(const void* const key, unsigned index)
 {
     assert(key);
 
-    set_node_parameters(key);
     for ( GHashNode* hnode = table[index]; hnode; hnode = hnode->next )
     {
         if ( keysize == 0 )
@@ -130,7 +120,7 @@ GHashNode* GHash::find_node(const void* const key)
         }
         else
         {
-            if ( hashfcn->keycmp_fcn(hnode->key, key, keysize) )
+            if ( hashfcn->key_compare(hnode->key, key, keysize) )
                 return hnode;
         }
     }
@@ -142,10 +132,11 @@ int GHash::insert(const void* const key, void* const data)
 {
     assert(key && data);
 
-    if ( GHashNode* hnode = find_node(key) )
+    unsigned index = get_index(key);
+    if ( GHashNode* hnode = find_node(key, index) )
     {
         cnode = hnode;
-        return GHASH_INTABLE;
+        return HASH_INTABLE;
     }
 
     GHashNode* hnode = (GHashNode*)snort_calloc(sizeof(GHashNode));
@@ -155,6 +146,7 @@ int GHash::insert(const void* const key, void* const data)
     }
     else
     {
+        unsigned klen = get_key_length(key);
         hnode->key = snort_alloc(klen);
         memcpy(const_cast<void*>(hnode->key), key, klen);
     }
@@ -177,14 +169,15 @@ int GHash::insert(const void* const key, void* const data)
 
     count++;
 
-    return GHASH_OK;
+    return HASH_OK;
 }
 
 void* GHash::find(const void* const key)
 {
     assert(key);
 
-    GHashNode* hnode = find_node(key);
+    unsigned index = get_index(key);
+    GHashNode* hnode = find_node(key, index);
     if ( hnode )
         return hnode->data;
 
@@ -219,17 +212,18 @@ int GHash::free_node(unsigned index, GHashNode* hnode)
     snort_free(hnode);
     count--;
 
-    return GHASH_OK;
+    return HASH_OK;
 }
 
 int GHash::remove(const void* const key)
 {
     assert(key);
 
-    if ( GHashNode* hnode = find_node(key) )
+    unsigned index = get_index(key);
+    if ( GHashNode* hnode = find_node(key, index) )
         return free_node(index, hnode);
     else
-        return GHASH_NOT_FOUND;
+        return HASH_NOT_FOUND;
 }
 
 void GHash::next()
@@ -272,9 +266,10 @@ GHashNode* GHash::find_next()
     return n;
 }
 
-void GHash::set_key_opcodes(hash_func hash_fcn, keycmp_func keycmp_fcn)
+void GHash::set_hashkey_ops(HashKeyOperations* hk)
 {
-    hashfcn_set_keyops(hashfcn, hash_fcn, keycmp_fcn);
+    delete hashfcn;
+    hashfcn = hk;
 }
 
 }
index 17b874e74ed444d12377c63961e73316f032982c..566a39a2da9a319192d5b612301860a492a70090 100644 (file)
 
 // generic hash table - stores and maps key + data pairs
 
+#include <string.h>
+#include "hash_key_operations.h"
 #include "main/snort_types.h"
 
-#include "hashfcn.h"
-
 namespace snort
 {
-#define GHASH_NOT_FOUND      (-1)
-#define GHASH_OK        0
-#define GHASH_INTABLE   1
-
 struct GHashNode
 {
     struct GHashNode* next;
     struct GHashNode* prev;
-    const void* key;  /* Copy of, or Pointer to, the Users key */
-    void* data;       /* The users data, this is never copied! */
+    const void* key;
+    void* data;
 };
 
 typedef void (* gHashFree)(void*);
@@ -55,31 +51,35 @@ public:
     void* find(const void* const key);
     GHashNode* find_first();
     GHashNode* find_next();
-    void set_key_opcodes(hash_func, keycmp_func);
+    void set_hashkey_ops(HashKeyOperations*);
 
     unsigned get_count() const
     { return count; }
 
 private:
-    void set_node_parameters(const void* const key);
-    GHashNode* find_node(const void* const key);
+    GHashNode* find_node(const void* const key, unsigned index);
     int free_node(unsigned index, GHashNode*);
     void next();
 
+    unsigned get_key_length(const void* const key)
+    { return ( keysize > 0  ) ? keysize : strlen((const char*)key) + 1; }
+
+    unsigned get_index(const void* const key)
+    {
+        unsigned hashkey = hashfcn->do_hash((const unsigned char*)key, get_key_length(key));
+        return hashkey % nrows;
+    }
+
     unsigned keysize;     // bytes in key, if < 0 -> keys are strings
     bool userkey;          // user owns the key */
     gHashFree userfree;
     int nrows;            // # rows int the hash table use a prime number 211, 9871
-    HashFnc* hashfcn;
+    HashKeyOperations* hashfcn;
     GHashNode** table;    // array of node ptr's
     unsigned count;       // total # nodes in table
     int crow;             // findfirst/next row in table
     GHashNode* cnode;     // findfirst/next node ptr
 
-    // node parameters for search/add/remove
-    unsigned klen = 0;
-    unsigned hashkey = 0;
-    int index = 0;
 };
 
 
index f66f16495c8c58f7884a42ad9bbfc4ddc262cb75..673da8eccdbf662a69ff15a7096328dab5a5b0eb 100644 (file)
 #ifndef HASH_DEFS_H
 #define HASH_DEFS_H
 
+#include "hash_key_operations.h"
 #include "main/snort_types.h"
-#include "utils/sfmemcap.h"
-
-#include "hashfcn.h"
 
 namespace snort
 {
-#define HASH_NOMEM    (-2)
-#define HASH_ERR      (-1)
+#define HASH_NOMEM     (-2)
+#define HASH_NOT_FOUND (-1)
 #define HASH_OK        0
 #define HASH_INTABLE   1
 #define HASH_PENDING   2
 
-struct HashNode
+class HashNode
 {
-    struct HashNode* gnext; // global node list - used for aging nodes
-    struct HashNode* gprev;
-    struct HashNode* next;  // row node list
-    struct HashNode* prev;
-    int rindex;     // row index of table this node belongs to.
-    void* key;      // Pointer to the key.
-    void* data;     // Pointer to the users data, this is not copied !
+public:
+    HashNode* gnext; // lru or free node list
+    HashNode* gprev;
+    HashNode* next;  // hash row node list
+    HashNode* prev;
+    void* key;
+    void* data;
+    int rindex;
 };
-
-typedef int (* Hash_FREE_FCN)(void* key, void* data);
 }
 #endif
similarity index 65%
rename from src/hash/hashfcn.cc
rename to src/hash/hash_key_operations.cc
index 12b73a49569ae7967cb17b5b68ba753edb8728e4..c70ff91d54edb118f0f37490ea5584de85b6537f 100644 (file)
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-/*
-     hashfcn.c
-
-     Each hash table allocates it's own GHash struct, using the number of
-     rows in the hash table to modulo the random values.
-
-     Updates:
-
-     8/31/2006 - man - changed to use sfprimetable.c
-*/
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
 
-#include "hashfcn.h"
+#include "hash_key_operations.h"
 
 #include <cassert>
 
 
 using namespace snort;
 
-static bool hashfcn_key_compare(const void* k1, const void* k2, size_t len)
-{
-    if ( memcmp(k1, k2, len ) == 0 )
-        return true;
-    else
-        return false;
-}
-
-HashFnc* hashfcn_new(int m)
+HashKeyOperations::HashKeyOperations(int rows)
 {
-    HashFnc* p;
-    static int one = 1;
+    static bool one = true;
 
     if ( one ) /* one time init */
     {
         srand( (unsigned)time(nullptr) );
-        one = 0;
+        one = false;
     }
 
-    p = (HashFnc*)snort_calloc(sizeof(*p));
-
     if ( SnortConfig::static_hash() )
     {
-        p->seed     = 3193;
-        p->scale    = 719;
-        p->hardener = 133824503;
+        seed = 3193;
+        scale = 719;
+        hardener = 133824503;
     }
     else
     {
-        p->seed = nearest_prime( (rand() % m) + 3191);
-        p->scale = nearest_prime( (rand() % m) + 709);
-        p->hardener = ((unsigned) rand() * rand()) + 133824503;
+        seed = nearest_prime( (rand() % rows) + 3191);
+        scale = nearest_prime( (rand() % rows) + 709);
+        hardener = ((unsigned) rand() * rand()) + 133824503;
     }
-
-    p->hash_fcn = &hashfcn_hash;
-    p->keycmp_fcn = &hashfcn_key_compare;
-
-    return p;
-}
-
-void hashfcn_free(HashFnc* p)
-{
-    if ( p )
-        snort_free(p);
 }
 
-unsigned hashfcn_hash(HashFnc* p, const unsigned char* d, int n)
+unsigned HashKeyOperations::do_hash(const unsigned char* key, int len)
 {
-    unsigned hash = p->seed;
-    while ( n )
+    unsigned hash = seed;
+    while ( len )
     {
-        hash *=  p->scale;
-        hash += *d++;
-        n--;
+        hash *= scale;
+        hash += *key++;
+        len--;
     }
-    return hash ^ p->hardener;
+    return hash ^ hardener;
 }
 
-/**
- * Make hashfcn use a separate set of opcodes for the backend.
- *
- * @param h hashfcn ptr
- * @param hash_fcn user specified hash function
- * @param keycmp_fcn user specified key comparison function
- */
-void hashfcn_set_keyops(HashFnc* h, hash_func hash_fcn, keycmp_func keycmp_fcn)
+bool HashKeyOperations::key_compare(const void* key1, const void* key2, size_t len)
 {
-    assert(h && hash_fcn && keycmp_fcn);
-
-    h->hash_fcn = hash_fcn;
-    h->keycmp_fcn = keycmp_fcn;
+    if ( memcmp(key1, key2, len) )
+        return false;
+    else
+        return true;
 }
 
 namespace snort
similarity index 83%
rename from src/hash/hashfcn.h
rename to src/hash/hash_key_operations.h
index ad56634049eac6deacc3ee269a38c9354ee68f4d..b48ab11fba297c5765df0df0d400f7e2af475925 100644 (file)
@@ -17,8 +17,8 @@
 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 //--------------------------------------------------------------------------
 
-#ifndef HASHFCN_H
-#define HASHFCN_H
+#ifndef HASH_KEY_OPERATIONS_H
+#define HASH_KEY_OPERATIONS_H
 
 #include "main/snort_types.h"
 
@@ -65,26 +65,22 @@ static inline int hash_nearest_power_of_2(int nrows)
     return nrows;
 }
 
-}
-
-struct HashFnc;
+class HashKeyOperations
+{
+public:
+    HashKeyOperations(int rows);
+    virtual ~HashKeyOperations()
+    { }
 
-typedef uint32_t (* hash_func)(HashFnc*, const unsigned char* d, int n);
-typedef bool (* keycmp_func)(const void* s1, const void* s2, size_t n);
+    virtual unsigned do_hash(const unsigned char* key, int len);
+    virtual bool key_compare(const void* key1, const void* key2, size_t len);
 
-struct HashFnc
-{
+protected:
     unsigned seed;
     unsigned scale;
     unsigned hardener;
-    hash_func hash_fcn;
-    keycmp_func keycmp_fcn;
 };
-
-HashFnc* hashfcn_new(int nrows);
-void hashfcn_free(HashFnc*);
-unsigned hashfcn_hash(HashFnc*, const unsigned char* d, int n);
-void hashfcn_set_keyops(HashFnc*, hash_func, keycmp_func);
+}
 
 #endif
 
diff --git a/src/hash/hash_lru_cache.cc b/src/hash/hash_lru_cache.cc
new file mode 100644 (file)
index 0000000..b155e59
--- /dev/null
@@ -0,0 +1,87 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// hash_lru_cache.cc author davis mcpherson davmcphe@cisco.com
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "hash_lru_cache.h"
+
+#include <cassert>
+#include "utils/util.h"
+
+using namespace snort;
+
+HashLruCache::HashLruCache()
+{
+    head = nullptr;
+    tail = nullptr;
+}
+
+void HashLruCache::insert(HashNode* hnode)
+{
+    if ( head )
+    {
+        hnode->gprev = nullptr;
+        hnode->gnext = head;
+        head->gprev = hnode;
+        head = hnode;
+    }
+    else
+    {
+        hnode->gprev = nullptr;
+        hnode->gnext = nullptr;
+        head = hnode;
+        tail = hnode;
+    }
+}
+
+void HashLruCache::touch(HashNode* hnode)
+{
+    if ( hnode == cursor )
+        cursor = hnode->gprev;
+
+    if ( hnode != head )
+    {
+        remove_node(hnode);
+        insert(hnode);
+    }
+}
+
+void HashLruCache::remove_node(HashNode* hnode)
+{
+    if ( cursor == hnode )
+        cursor = hnode->gprev;
+
+    if ( head == hnode )
+    {
+        head = head->gnext;
+        if ( head )
+            head->gprev = nullptr;
+    }
+
+    if ( hnode->gprev )
+        hnode->gprev->gnext = hnode->gnext;
+    if ( hnode->gnext )
+        hnode->gnext->gprev = hnode->gprev;
+
+    if ( tail == hnode )
+        tail = hnode->gprev;
+}
diff --git a/src/hash/hash_lru_cache.h b/src/hash/hash_lru_cache.h
new file mode 100644 (file)
index 0000000..6436c39
--- /dev/null
@@ -0,0 +1,73 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// hash_lru_cache.h author davis mcpherson davmcphe@cisco.com
+
+#ifndef HASH_LRU_CACHE_H
+#define HASH_LRU_CACHE_H
+
+#include "hash_defs.h"
+
+class HashLruCache
+{
+public:
+    HashLruCache();
+
+    void insert(snort::HashNode*);
+    void touch(snort::HashNode*);
+    void remove_node(snort::HashNode*);
+
+    snort::HashNode* get_lru_node()
+    {
+        cursor = tail;
+        return cursor;
+    }
+
+    snort::HashNode* get_next_lru_node()
+    {
+        if ( cursor )
+            cursor = cursor->gprev;
+        return cursor;
+    }
+
+    snort::HashNode* get_current_node()
+    { return cursor; }
+
+    void* get_mru_user_data()
+    { return ( head ) ? head->data : nullptr; }
+
+    void* get_lru_user_data()
+    { return ( tail ) ? tail->data : nullptr; }
+
+    snort::HashNode* remove_lru_node()
+    {
+        snort::HashNode* hnode = tail;
+        if ( hnode )
+            remove_node(hnode);
+
+        return hnode;
+    }
+
+private:
+    snort::HashNode* head = nullptr;
+    snort::HashNode* tail = nullptr;
+    snort::HashNode* cursor = nullptr;
+};
+
+#endif
+
index 39896fa9b8e64d5d6e1cab53fad59f6ed20ba8f4..20e176d8b16743c6e7cdb320f62d58181d0c1482 100644 (file)
@@ -2,17 +2,31 @@ add_cpputest( lru_cache_shared_test
     SOURCES ../lru_cache_shared.cc
 )
 
+add_cpputest( hash_lru_cache_test
+    SOURCES ../hash_lru_cache.cc
+)
+
 add_cpputest( xhash_test
     SOURCES
-        ../xhash.cc
-        ../hashfcn.cc
+        ../hash_key_operations.cc
+        ../hash_lru_cache.cc
         ../primetable.cc
-        ../../utils/sfmemcap.cc
+        ../xhash.cc
 )
 
 add_cpputest( ghash_test
     SOURCES
         ../ghash.cc
-        ../hashfcn.cc
+        ../hash_key_operations.cc
+        ../hash_lru_cache.cc
         ../primetable.cc
 )
+
+add_cpputest( zhash_test
+    SOURCES
+        ../hash_key_operations.cc
+        ../hash_lru_cache.cc
+        ../primetable.cc
+        ../xhash.cc
+        ../zhash.cc
+)
index c1175a9cc98fa9ac337b063be4e2d7d6b3c068d9..fba122d4468ced1df3f1445d2bc582d4baa5b11b 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "hash/ghash.h"
 
+#include "hash/hash_defs.h"
 #include "main/snort_config.h"
 #include "utils/util.h"
 
@@ -119,7 +120,7 @@ TEST(ghash, collision_test)
     snprintf(str, sizeof(str), "KeyWord%d",1);
     str[sizeof(str) - 1] = '\0';
     i = t->insert(str, (void *)(str + (1)));
-    CHECK(i == GHASH_INTABLE);
+    CHECK(i == HASH_INTABLE);
 
     // find those nodes
     for (i=num-1; i>=0; i--)
@@ -192,7 +193,7 @@ TEST(ghash, userfree_test)
     CHECK(t->find(str) == nullptr);
     
     // try to remove a node that is not in the table
-    CHECK(t->remove( str) == GHASH_NOT_FOUND);
+    CHECK(t->remove( str) == HASH_NOT_FOUND);
 
     for ( GHashNode* n = t->find_first(); n; n = t->find_next() )
     {
diff --git a/src/hash/test/hash_lru_cache_test.cc b/src/hash/test/hash_lru_cache_test.cc
new file mode 100644 (file)
index 0000000..5a28774
--- /dev/null
@@ -0,0 +1,140 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// hash_lru_cache_test.cc author davis mcpherson <davmcphe@cisco.com>
+// unit tests for the HashLruCache class
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../hash_lru_cache.h"
+
+#include "../../utils/util.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+using namespace snort;
+
+HashLruCache* lru = nullptr;
+
+TEST_GROUP(hash_lru_cache)
+{
+    void setup() override
+    {
+        lru = new HashLruCache;
+        CHECK(lru);
+    }
+
+    void teardown() override
+    {
+        unsigned node_id = 1;
+        HashNode* node = lru->remove_lru_node();
+        while( node )
+        {
+            CHECK(*(unsigned*)node->data == node_id);
+            unsigned* data = (unsigned *)lru->get_mru_user_data();
+            if ( data )
+                CHECK(*data == 5);
+            data = (unsigned *)lru->get_lru_user_data();
+            if ( data )
+                CHECK(*data == node_id + 1);
+            ++node_id;
+            delete (unsigned*)node->data;
+            snort_free(node);
+            node = lru->remove_lru_node();
+        }
+
+        delete lru;
+    }
+};
+
+TEST(hash_lru_cache, create_hash_lru_cache_test)
+{
+    CHECK(!lru->get_next_lru_node());
+    CHECK(!lru->get_current_node());
+    CHECK(!lru->get_mru_user_data());
+    CHECK(!lru->get_lru_user_data());
+    CHECK(!lru->remove_lru_node());
+}
+
+TEST(hash_lru_cache, hash_lru_cache_insert_test)
+{
+    HashNode* node;
+    for (unsigned i = 0; i < 5; i++)
+    {
+        node = (HashNode*)snort_calloc(sizeof(HashNode));
+        unsigned* data = new unsigned;
+        *data = i + 1;
+        node->data = data;
+        lru->insert(node);
+        CHECK(*((unsigned *)lru->get_mru_user_data()) == i + 1);
+        CHECK(*((unsigned *)lru->get_lru_user_data()) == 1);
+    }
+
+    for (unsigned i = 0; i < 5; i++)
+    {
+        node = lru->get_lru_node();
+        CHECK(node);
+        CHECK(*((unsigned*)node->data) == i + 1);
+        lru->touch(node);
+        CHECK(*((unsigned *)lru->get_mru_user_data()) == i + 1);
+        CHECK(*((unsigned *)lru->get_lru_user_data()) == ((i + 1) % 5) + 1);
+    }
+
+    node = lru->get_lru_node();
+    CHECK(node);
+    CHECK(*((unsigned*)node->data) == 1);
+}
+
+TEST(hash_lru_cache, hash_lru_cache_browse_test)
+{
+    HashNode* node;
+    for (unsigned i = 0; i < 5; i++)
+    {
+        node = (HashNode*)snort_calloc(sizeof(HashNode));
+        unsigned* data = new unsigned;
+        *data = i + 1;
+        node->data = data;
+        lru->insert(node);
+    }
+
+    for (unsigned i = 0; i < 5; i++)
+    {
+        node = lru->get_lru_node();
+        CHECK(node);
+        CHECK(*((unsigned*)node->data) == (i + 1));
+        lru->touch(node);
+    }
+
+    node = lru->get_lru_node();
+    unsigned i = 1;
+    while( node )
+    {
+        CHECK(*(unsigned*)node->data == i);
+        CHECK(*(unsigned*)lru->get_current_node()->data == i);
+        node = lru->get_next_lru_node();
+        ++i;
+    }
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
index a52a4d92d8ec7efab3eb5b504d1775af805fd313..96002f4e8f4718856c62fa6547fdbbc1fd45302f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "hash/xhash.h"
 
+#include "hash/hash_defs.h"
 #include "main/snort_config.h"
 #include "utils/util.h"
 
@@ -56,9 +57,8 @@ TEST_GROUP(xhash)
 //  Test create a hash table, add nodes, find and delete.
 TEST(xhash, create_xhash_test)
 {
-    XHash* test_table = new XHash(4, sizeof(struct xhash_test_key),
-                                  0, 0, false, nullptr, nullptr, false);
-    CHECK(test_table->get_keysize() == sizeof(struct xhash_test_key));
+    XHash* test_table = new XHash(4, sizeof(struct xhash_test_key), 0, 0);
+    CHECK(test_table);
 
     void* data = test_table->get_mru_user_data();
     CHECK(data == nullptr);
@@ -84,39 +84,40 @@ TEST(xhash, create_xhash_test)
 // Create a free node in xhash and verifies if xhash_free_anr_lru() deletes it
 TEST(xhash, free_anr_lru_delete_free_node_test)
 {
-    XHash* test_table = new XHash(3, sizeof(struct xhash_test_key),
-                                  1, 1040, false, nullptr, nullptr, true);
+    XHash* test_table = new XHash(3, sizeof(struct xhash_test_key), 1, 1040);
+    CHECK(test_table);
+
     xhash_test_key xtk;
     xtk.key = 10;
     int ret = test_table->insert(&xtk, nullptr);
     CHECK(ret == HASH_OK);
 
-     HashNode* xnode = test_table->get_node(&xtk);
-    CHECK(xnode != nullptr);
+     HashNode* xnode = test_table->find_node(&xtk);
+    CHECK(xnode);
 
     ret = test_table->release_node(xnode);
     CHECK(ret == HASH_OK);
 
-    ret = test_table->delete_anr_or_lru_node();
+    ret = test_table->delete_lru_node();
     CHECK(ret == HASH_OK);
 
     HashNode* xhnode = test_table->find_node(&xtk);
-    CHECK(xhnode == nullptr);
+    CHECK(!xhnode);
 
     delete test_table;
 }
 
-// No free node is available, verifies if xhash_free_anr_lru() deletes the last node
+// No free node is available, verifies the LRU node is deleted
 TEST(xhash, free_anr_lru_delete_tail_node_test)
 {
-    XHash* test_table = new XHash(3, sizeof(struct xhash_test_key),
-                                  1, 1040, false, nullptr, nullptr, true);
+    XHash* test_table = new XHash(3, sizeof(struct xhash_test_key), 1, 1040);
+    CHECK(test_table);
+
     xhash_test_key xtk;
     int ret = test_table->insert(&xtk, nullptr);
     CHECK(ret == HASH_OK);
 
-    ret = test_table->delete_anr_or_lru_node();
-    CHECK(ret == HASH_OK);
+    CHECK(test_table->delete_lru_node());
 
     HashNode* xhnode = test_table->find_node(&xtk);
     CHECK(xhnode == nullptr);
@@ -124,20 +125,6 @@ TEST(xhash, free_anr_lru_delete_tail_node_test)
     delete test_table;
 }
 
-// No free node is available [recycle is not enabled], verifies if last node is deleted
-TEST(xhash, free_anr_lru_usr_free_delete_tail_node_test)
-{
-    XHash* test_table = new XHash(3, sizeof(struct xhash_test_key),
-                                  1, 1040, false, nullptr, nullptr, false);
-    xhash_test_key xtk;
-    int ret = test_table->insert(&xtk, nullptr);
-    CHECK(ret == HASH_OK);
-
-    ret = test_table->delete_anr_or_lru_node();
-    CHECK(ret == HASH_OK);
-    delete test_table;
-}
-
 int main(int argc, char** argv)
 {
     return CommandLineTestRunner::RunAllTests(argc, argv);
diff --git a/src/hash/test/zhash_test.cc b/src/hash/test/zhash_test.cc
new file mode 100644 (file)
index 0000000..93e4817
--- /dev/null
@@ -0,0 +1,149 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// zhash_test.cc author davis mcpherson <davmcphe@cisco.com>
+// unit tests for the HashLruCache class
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <string>
+
+#include "../zhash.h"
+#include "../hash_key_operations.h"
+
+#include "flow/flow_key.h"
+#include "main/snort_config.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+using namespace snort;
+
+namespace snort
+{
+unsigned FlowHashKeyOps::do_hash(const unsigned char* k, int len)
+{
+    unsigned hash = seed;
+    while ( len )
+    {
+        hash *= scale;
+        hash += *k++;
+        len--;
+    }
+    return hash ^ hardener;
+}
+
+bool FlowHashKeyOps::key_compare(const void* k1, const void* k2, size_t len)
+{
+    if ( memcmp(k1, k2, len ) == 0 )
+        return true;
+    else
+        return false;
+}
+}
+
+// Stubs whose sole purpose is to make the test code link
+static SnortConfig my_config;
+THREAD_LOCAL SnortConfig *snort_conf = &my_config;
+
+SnortConfig::SnortConfig(const SnortConfig* const)
+{ snort_conf->run_flags = 0;} // run_flags is used indirectly from HashFnc class by calling SnortConfig::static_hash()
+
+SnortConfig::~SnortConfig() = default;
+
+SnortConfig* SnortConfig::get_conf()
+{ return snort_conf; }
+
+const unsigned ZHASH_ROWS = 1000;
+const unsigned ZHASH_KEY_SIZE = 100;
+const unsigned MAX_ZHASH_NODES = 100;
+char key_buf[ZHASH_KEY_SIZE];
+
+ZHash* zh = nullptr;
+
+TEST_GROUP(zhash)
+{
+    void setup() override
+    {
+        zh = new ZHash(ZHASH_ROWS, ZHASH_KEY_SIZE);
+        CHECK(zh);
+
+        memset(key_buf, '\0', ZHASH_KEY_SIZE);
+    }
+
+    void teardown() override
+    {
+        delete zh;
+    }
+};
+
+TEST(zhash, create_zhash_test)
+{
+    for (unsigned i = 0; i < MAX_ZHASH_NODES; i++ )
+    {
+        unsigned* data;
+        data = (unsigned*)snort_calloc(sizeof(unsigned));
+        *data = 0;
+        zh->push(data);
+    }
+
+    std::string key_prefix = "foo";
+    for (unsigned i = 0; i < MAX_ZHASH_NODES; i++ )
+     {
+        std::string key;
+        key = key_prefix + std::to_string(i + 1);
+        memcpy(key_buf, key.c_str(), key.size());
+        unsigned* data = (unsigned*)zh->get(key_buf);
+        CHECK(*data == 0);
+        *data = i + 1;
+     }
+
+    unsigned nodes_walked = 0;
+    unsigned* data = (unsigned*)zh->lru_first();
+    while ( data )
+    {
+        CHECK(*data == ++nodes_walked);
+        data = (unsigned*)zh->lru_next();
+    }
+
+    CHECK(nodes_walked == MAX_ZHASH_NODES);
+
+    data = (unsigned*)zh->lru_first();
+    CHECK(*data == 1);
+    data = (unsigned*)zh->remove();
+    CHECK(*data == 1);
+    snort_free(data);
+    data = (unsigned*)zh->lru_current();
+    CHECK(*data == 2);
+    data = (unsigned*)zh->lru_first();
+    CHECK(*data == 2);
+
+    for (unsigned i = 1; i < MAX_ZHASH_NODES; i++ )
+     {
+        data = (unsigned*)zh->remove();
+        CHECK(*data == (i + 1));
+        snort_free(data);
+     }
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}
index bcca7c412cba7fe7e670d4f8f753a88b4e8ea114..ee7d741524aa748038b00e811ce8d671fa39ab70 100644 (file)
 #include <cassert>
 #include "utils/util.h"
 
+#include "hash_defs.h"
+#include "hash_key_operations.h"
+#include "hash_lru_cache.h"
+
 using namespace snort;
 
 namespace snort
 {
 
-XHash::XHash(int nrows_, int keysize_, int datasize_, unsigned long maxmem,
-    bool anr_enabled, Hash_FREE_FCN anr_free, Hash_FREE_FCN usr_free,
-    bool recycle_nodes)
-    : keysize(keysize_), datasize(datasize_), recycle_nodes(recycle_nodes),
-      anr_enabled(anr_enabled), anr_free(anr_free), usr_free(usr_free)
+void XHash::initialize(HashKeyOperations* hk_ops)
+{
+    hashkey_ops = hk_ops;
+    table = (HashNode**)snort_calloc(sizeof(HashNode*) * nrows);
+    lru_cache = new HashLruCache();
+    mem_allocator = new MemCapAllocator(mem_cap, sizeof(HashNode) + keysize + datasize);
+}
+
+void XHash::initialize()
+{
+    initialize(new HashKeyOperations(nrows));
+}
+
+void XHash::set_number_of_rows (int rows)
 {
-    // adjust rows to be power of 2
-    if ( nrows_ > 0 )
-        nrows = hash_nearest_power_of_2(nrows_);
+    if ( rows > 0 )
+        nrows = hash_nearest_power_of_2 (rows);
     else
-        nrows = -nrows_;       // if negative use as is
+        nrows = -rows;
+}
 
-    table = (HashNode**)snort_calloc(sizeof(HashNode*) * nrows);
-    hashfcn = hashfcn_new(nrows);
-    sfmemcap_init(&mc, maxmem);
+XHash::XHash(int rows, int keysize)
+    : keysize(keysize)
 
-    for ( unsigned i = 0; i < nrows; i++ )
-        table[i] = nullptr;
+{
+    set_number_of_rows(rows);
+}
 
-    mem_allocated_per_entry = sizeof(HashNode) + keysize + datasize + sizeof(long);
+XHash::XHash(int rows, int keysize, int datasize, unsigned long memcap)
+    : keysize(keysize), datasize(datasize), mem_cap(memcap)
+{
+    set_number_of_rows(rows);
+    initialize();
 }
 
 XHash::~XHash()
 {
-    if ( hashfcn )
-        hashfcn_free(hashfcn);
-
-    for (unsigned i = 0; i < nrows; i++)
+    if ( table )
     {
-        for ( HashNode* node = table[i]; node; )
-        {
-            HashNode* onode = node;
-            node  = node->next;
-
-            if ( usr_free )
-                usr_free(onode->key, onode->data);
+        for (unsigned i = 0; i < nrows; i++)
+            for (HashNode* node = table[i]; node;)
+            {
+                HashNode* xnode;
+                xnode = node;
+                node = node->next;
+                mem_allocator->free(xnode);
+            }
 
-            sfmemcap_free(&mc, onode);
-        }
+        snort_free(table);
     }
-    snort_free(table);
+
     purge_free_list();
+    delete hashkey_ops;
+    delete lru_cache;
+    delete mem_allocator;
 }
 
-void XHash::clear()
+void XHash::delete_hash_table()
 {
+    assert( table );
+
     for (unsigned i = 0; i < nrows; i++)
-    {
-        HashNode* n = table[i];
-        while ( n )
+        for (HashNode* node = table[i]; node;)
         {
-            HashNode* tmp;
-            tmp = n;
-            n = n->next;
-            release_node(tmp);
+            HashNode* xnode;
+            xnode = node;
+            node = node->next;
+            free_user_data(xnode);
+            mem_allocator->free(xnode);
         }
-    }
 
-    max_nodes = 0;
-    crow = 0;
-    cnode = nullptr;
-    count = 0;
-    ghead = nullptr;
-    gtail = nullptr;
-    anr_count = 0;
-    anr_tries = 0;
-    find_success = 0;
-    find_fail = 0;
+    snort_free(table);
+    table = nullptr;
 }
 
-void XHash::save_free_node(HashNode* hnode)
+void XHash::initialize_node(HashNode *hnode, const void *key, void *data, int index)
 {
-    if ( fhead )
+    hnode->key = (char*) (hnode) + sizeof(HashNode);
+    memcpy(hnode->key, key, keysize);
+    if ( datasize )
     {
-        hnode->gprev    = nullptr;
-        hnode->gnext    = fhead;
-        fhead->gprev = hnode;
-        fhead        = hnode;
+        hnode->data = (char*) (hnode) + sizeof(HashNode) + keysize;
+        if ( data )
+            memcpy (hnode->data, data, datasize);
     }
     else
-    {
-        hnode->gprev = nullptr;
-        hnode->gnext = nullptr;
-        fhead    = hnode;
-        ftail    = hnode;
-    }
+        hnode->data = data;
+
+    hnode->rindex = index;
+    link_node(hnode);
+    lru_cache->insert(hnode);
 }
 
-HashNode* XHash::get_free_node()
+HashNode* XHash::allocate_node(const void* key, void* data, int index)
 {
-    HashNode* node = fhead;
+    // use a free one if available...
+    HashNode* hnode = get_free_node();
 
-    if ( fhead )
-    {
-        fhead = fhead->gnext;
-        if ( fhead )
-            fhead->gprev = nullptr;
+    // if no free nodes, try to allocate a new one...
+    if ( !hnode && ((max_nodes == 0) || (num_nodes < max_nodes)) )
+        hnode = (HashNode*)mem_allocator->allocate();
 
-        if ( ftail == node )
-            ftail = nullptr;
+    // if still no node then try to reuse one...
+    if ( !hnode && anr_enabled )
+        hnode = release_lru_node();
+
+    if ( hnode )
+    {
+        initialize_node(hnode, key, data, index);
+        ++num_nodes;
     }
 
-    return node;
+    return hnode;
 }
 
-void XHash::purge_free_list()
+int XHash::insert(const void* key, void* data)
 {
-    HashNode* cur = fhead;
-    while ( cur )
+    assert(key);
+
+    int index = 0;
+    HashNode* hnode = find_node_row(key, index);
+    if ( hnode )
     {
-        HashNode* next = cur->gnext;
-        sfmemcap_free(&mc, (void*)cur);
-        cur = next;
+        cursor = hnode;
+        return HASH_INTABLE;
     }
 
-    fhead = nullptr;
-    ftail = nullptr;
+    hnode = allocate_node(key, data, index);
+    cursor = hnode;
+    return ( hnode ) ? HASH_OK : HASH_NOMEM;
 }
 
-void XHash::glink_node(HashNode* hnode)
+HashNode* XHash::find_node(const void* key)
 {
-    if ( ghead )
-    {
-        hnode->gprev = nullptr;
-        hnode->gnext = ghead;
-        ghead->gprev = hnode;
-        ghead = hnode;
-    }
-    else
-    {
-        hnode->gprev = nullptr;
-        hnode->gnext = nullptr;
-        ghead = hnode;
-        gtail = hnode;
-    }
+    assert(key);
+
+    int rindex = 0;
+    return find_node_row(key, rindex);
 }
 
-void XHash::gunlink_node(HashNode* hnode)
+HashNode* XHash::find_first_node()
 {
-    if ( gnode == hnode )
-        gnode = hnode->gnext;
-
-    if ( ghead == hnode )
+    for ( crow = 0; crow < nrows; crow++ )
     {
-        ghead = ghead->gnext;
-        if ( ghead )
-            ghead->gprev = nullptr;
+        cursor = table[crow];
+        if ( cursor )
+        {
+            HashNode* n = cursor;
+            update_cursor();
+            return n;
+        }
     }
 
-    if ( hnode->gprev )
-        hnode->gprev->gnext = hnode->gnext;
-    if ( hnode->gnext )
-        hnode->gnext->gprev = hnode->gprev;
+    return nullptr;
+}
 
-    if ( gtail == hnode )
-        gtail = hnode->gprev;
+HashNode* XHash::find_next_node()
+{
+    HashNode* n = cursor;
+    if ( !n )
+        return nullptr;
+
+    update_cursor();
+    return n;
 }
 
-void XHash::gmove_to_front(HashNode* hnode)
+void* XHash::get_user_data()
 {
-    if ( hnode != ghead )
+    if ( cursor )
+        return cursor->data;
+    else
+        return nullptr;
+}
+
+void XHash::update_cursor()
+{
+    if ( !cursor )
+        return;
+
+    cursor = cursor->next;
+    if ( cursor )
+        return;
+
+    for ( crow++; crow < nrows; crow++ )
     {
-        gunlink_node(hnode);
-        glink_node(hnode);
+        cursor = table[crow];
+        if ( cursor )
+            return;
     }
 }
 
-HashNode* XHash::gfind_next()
+void* XHash::get_user_data(const void* key)
 {
-    HashNode* n = gnode;
-    if ( n )
-        gnode = n->gnext;
-    return n;
+    assert(key);
+
+    int rindex = 0;
+    HashNode* hnode = find_node_row(key, rindex);
+    return ( hnode ) ? hnode->data : nullptr;
 }
 
-HashNode* XHash::gfind_first()
+void XHash::release()
 {
-    if ( ghead )
-        gnode = ghead->gnext;
-    else
-        gnode = nullptr;
-    return ghead;
+    HashNode* node = lru_cache->get_current_node();
+    assert(node);
+    release_node(node);
 }
 
-void* XHash::get_mru_user_data()
+int XHash::release_node(HashNode* hnode)
 {
-    if ( ghead )
-        return ghead->data;
+    assert(hnode);
+
+    free_user_data(hnode);
+    unlink_node(hnode);
+    lru_cache->remove_node(hnode);
+    num_nodes--;
+
+    if ( recycle_nodes )
+    {
+        save_free_node(hnode);
+        ++stats.release_recycles;
+    }
     else
-        return nullptr;
+    {
+        mem_allocator->free(hnode);
+        ++stats.release_deletes;
+    }
+
+    return HASH_OK;
 }
 
-void* XHash::get_lru_user_data()
+int XHash::release_node(const void* key)
 {
-    if ( gtail )
-        return gtail->data;
-    else
-        return nullptr;
+    assert(key);
+
+    unsigned hashkey = hashkey_ops->do_hash((const unsigned char*)key, keysize);
+
+    unsigned index = hashkey & (nrows - 1);
+    for (HashNode* hnode = table[index]; hnode; hnode = hnode->next)
+    {
+        if ( hashkey_ops->key_compare(hnode->key, key, keysize) )
+            return release_node(hnode);
+    }
+
+    return HASH_NOT_FOUND;
 }
 
 void XHash::link_node(HashNode* hnode)
@@ -333,327 +383,172 @@ void XHash::unlink_node(HashNode* hnode)
     }
 }
 
-void XHash::move_to_front(HashNode* n)
+void XHash::move_to_front(HashNode* node)
 {
-    if ( table[n->rindex] != n )
+    if ( table[node->rindex] != node )
     {
-        unlink_node(n);
-        link_node(n);
+        unlink_node(node);
+        link_node(node);
     }
 
-    if (n == gnode)
-        gnode = n->gnext;
-    gmove_to_front(n);
+    lru_cache->touch(node);
 }
 
-/*
- * Allocate a new hash node, uses Auto Node Recovery if needed and enabled.
- *
- * The oldest node is the one with the longest time since it was last touched,
- * and does not have any direct indication of how long the node has been around.
- * We don't monitor the actual time since last being touched, instead we use a
- * splayed global list of node pointers. As nodes are accessed they are splayed
- * to the front of the list. The oldest node is just the tail node.
- *
- */
-HashNode* XHash::allocate_node()
+HashNode* XHash::find_node_row(const void* key, int& rindex)
 {
-    // use previously allocated node if there is a free one...
-    HashNode* hnode = get_free_node();
-    if ( !hnode )
-    {
-        if ( (max_nodes == 0) || (count < max_nodes) )
-            hnode = (HashNode*)sfmemcap_alloc(&mc,
-                sizeof(HashNode) + keysize + datasize);
+    unsigned hashkey = hashkey_ops->do_hash((const unsigned char*)key, keysize);
 
-        if ( !hnode && anr_enabled && gtail )
-        {
-            /* Find the oldest node the users willing to let go. */
-            for (hnode = gtail; hnode; hnode = hnode->gprev )
-            {
-                if ( anr_free )
-                {
-                    anr_tries++;
-                    if ( anr_free(hnode->key, hnode->data) )
-                        continue;   // don't recycle this one...
-                }
-
-                gunlink_node(hnode);
-                unlink_node(hnode);
-                count--;
-                anr_count++;
-                break;
-            }
-        }
-    }
-
-    return hnode;
-}
-
-HashNode* XHash::find_node_row(const void* key, int* rindex)
-{
-    unsigned hashkey = hashfcn->hash_fcn(hashfcn, (const unsigned char*)key, keysize);
-
-    // Modulus is slow. masking since table size is a power of 2.
-    int index  = hashkey & (nrows - 1);
-    *rindex = index;
-
-    for (HashNode* hnode = table[index]; hnode; hnode = hnode->next )
+    /* Modulus is slow. Switched to a table size that is a power of 2. */
+    rindex  = hashkey & (nrows - 1);
+    for (HashNode* hnode = table[rindex]; hnode; hnode = hnode->next )
     {
-        if ( hashfcn->keycmp_fcn(hnode->key, key, keysize) )
+        if ( hashkey_ops->key_compare(hnode->key, key, keysize) )
         {
-            if ( splay > 0 )
-                move_to_front(hnode);
-
-            find_success++;
+            move_to_front(hnode);
             return hnode;
         }
     }
 
-    find_fail++;
     return nullptr;
 }
 
-int XHash::insert(const void* key, void* data)
+void XHash::save_free_node(HashNode* hnode)
 {
-    assert(key);
-
-    int index = 0;
-
-    /* Enforce uniqueness: Check for the key in the table */
-    HashNode* hnode = find_node_row(key, &index);
-    if ( hnode )
+    if ( fhead )
     {
-        cnode = hnode;
-        return HASH_INTABLE;
+        hnode->gprev = nullptr;
+        hnode->gnext = fhead;
+        fhead->gprev = hnode;
+        fhead = hnode;
     }
-
-    hnode = allocate_node();
-    if ( !hnode )
-        return HASH_NOMEM;
-
-    hnode->key = (char*)hnode + sizeof(HashNode);
-    memcpy(hnode->key, key, keysize);
-    hnode->rindex = index;
-
-    if ( datasize )
+    else
     {
-        hnode->data = (char*)hnode + sizeof(HashNode) + keysize;
-        if ( data )
-            memcpy(hnode->data, data, datasize);
+        hnode->gprev = nullptr;
+        hnode->gnext = nullptr;
+        fhead = hnode;
     }
-    else
-        hnode->data = data;
-
-    link_node (hnode);
-    glink_node(hnode);
-    count++;
-
-    return HASH_OK;
 }
 
-HashNode* XHash::get_node(const void* key)
+HashNode* XHash::get_free_node()
 {
-    assert(key);
-
-    int index = 0;
-
-    // Enforce uniqueness: Check for the key in the table
-    HashNode* hnode = find_node_row( key, &index);
-    if ( hnode )
+    HashNode* node = fhead;
+    if ( fhead )
     {
-        cnode = hnode;
-        return hnode;
+        fhead = fhead->gnext;
+        if ( fhead )
+            fhead->gprev = nullptr;
     }
 
-    hnode = allocate_node();
-    if ( !hnode )
-        return nullptr;
-
-    hnode->key = (char*)hnode + sizeof(HashNode);
-    memcpy(hnode->key, key, keysize);
-    hnode->rindex = index;
-
-    if ( datasize )
-        hnode->data = (char*)hnode + sizeof(HashNode) + keysize;
-    else
-        hnode->data = nullptr;
-
-    link_node(hnode);
-    glink_node(hnode);
-    count++;
-
-    return hnode;
-}
-
-HashNode* XHash::get_node_with_prune(const void* key, bool* prune_performed)
-{
-    assert(key);
-
-    size_t mem_after_alloc = mc.memused + mem_allocated_per_entry;
-    bool over_capacity = (mc.memcap < mem_after_alloc);
-
-    if ( over_capacity )
-        *prune_performed = (delete_anr_or_lru_node() == HASH_OK);
-
-    HashNode* hnode = nullptr;
-    if ( *prune_performed or !over_capacity )
-        hnode = get_node(key);
-
-    return hnode;
+    return node;
 }
 
-HashNode* XHash::find_node(const void* key)
+bool XHash::delete_free_node()
 {
-    assert(key);
-
-    int rindex = 0;
-    return find_node_row(key, &rindex);
+    HashNode* hnode = get_free_node();
+    if ( hnode )
+    {
+        mem_allocator->free(hnode);
+        return true;
+    }
+    return false;
 }
 
-void* XHash::get_user_data(void* key)
+void XHash::purge_free_list()
 {
-    assert(key);
-
-    int rindex = 0;
-    HashNode* hnode = find_node_row(key, &rindex);
-    if ( hnode )
-        return hnode->data;
+    HashNode* cur = fhead;
+    while ( cur )
+    {
+        HashNode* next = cur->gnext;
+        mem_allocator->free(cur);
+        cur = next;
+    }
 
-    return nullptr;
+    fhead = nullptr;
 }
 
-int XHash::release_node(HashNode* hnode)
+void XHash::clear_hash()
 {
-    assert(hnode);
-
-    unlink_node(hnode);
-    gunlink_node(hnode);
-    count--;
-
-    if ( usr_free )
-        usr_free(hnode->key, hnode->data);
-
-    if ( recycle_nodes )
-        save_free_node(hnode);
-    else
-        sfmemcap_free(&mc, hnode);
+    for (unsigned i = 0; i < nrows; i++)
+        for (HashNode* node = table[i]; node;)
+        {
+            HashNode* xnode = node;
+            node = node->next;
+            release_node(xnode);
+        }
 
-    return HASH_OK;
+    max_nodes = 0;
+    num_nodes = 0;
+    crow = 0;
+    cursor = nullptr;
 }
 
-int XHash::release_node(void* key)
+void* XHash::get_mru_user_data()
 {
-    assert(key);
-
-    unsigned hashkey = hashfcn->hash_fcn(hashfcn, (unsigned char*)key, keysize);
-
-    unsigned index = hashkey & (nrows - 1);
-    for ( HashNode* hnode = table[index]; hnode; hnode = hnode->next )
-    {
-        if ( hashfcn->keycmp_fcn(hnode->key, key, keysize) )
-            return release_node(hnode);
-    }
-
-    return HASH_ERR;
+    return lru_cache->get_mru_user_data();
 }
 
-int XHash::delete_free_node()
+void* XHash::get_lru_user_data()
 {
-    HashNode* fn = get_free_node();
-    if (fn)
-    {
-        sfmemcap_free(&mc, fn);
-        return HASH_OK;
-    }
-    return HASH_ERR;
+    return lru_cache->get_lru_user_data();
 }
 
-int XHash::delete_anr_or_lru_node()
+HashNode* XHash::release_lru_node()
 {
-    if ( fhead )
+    HashNode* hnode = lru_cache->get_lru_node();
+    while ( hnode )
     {
-        if (delete_free_node() == HASH_OK)
-            return HASH_OK;
-    }
-
-    if ( gtail )
-    {
-        if ( release_node(gtail) == HASH_OK )
+        if ( is_node_recovery_ok(hnode) )
         {
-            if ( fhead )
-            {
-                if ( delete_free_node() == HASH_OK )
-                    return HASH_OK;
-            }
-            else if ( !recycle_nodes )
-                return HASH_OK;
+            lru_cache->remove_node(hnode);
+            free_user_data(hnode);
+            unlink_node(hnode);
+            --num_nodes;
+            ++stats.memcap_prunes;
+            break;
         }
+        else
+            hnode = lru_cache->get_next_lru_node ();
     }
-    return HASH_ERR;
+    return hnode;
 }
 
-int XHash::free_over_allocations(unsigned work_limit, unsigned* num_freed)
+bool XHash::delete_lru_node()
 {
-
-    while (mc.memcap < mc.memused and work_limit--)
+    if ( HashNode* hnode = lru_cache->remove_lru_node() )
     {
-        if (delete_anr_or_lru_node() != HASH_OK)
-            return HASH_ERR;
-
-        ++*num_freed;
+        unlink_node(hnode);
+        free_user_data(hnode);
+        mem_allocator->free(hnode);
+        --num_nodes;
+        return true;
     }
 
-    return (mc.memcap >= mc.memused) ? HASH_OK : HASH_PENDING;
+    return false;
 }
 
-void XHash::update_cnode()
+bool XHash::delete_a_node()
 {
-    if ( !cnode )
-        return;
+    if ( delete_free_node() )
+        return true;
 
-    cnode = cnode->next;
-    if ( cnode )
-        return;
+    if ( delete_lru_node() )
+        return true;
 
-    for ( crow++; crow < nrows; crow++ )
-    {
-        cnode = table[crow];
-        if ( cnode )
-            return;
-    }
+    return false;
 }
 
-HashNode* XHash::find_first_node()
+int XHash::tune_memory_resources(unsigned work_limit, unsigned& num_freed)
 {
-    for ( crow = 0; crow < nrows; crow++ )
+    while ( work_limit-- and mem_allocator->is_over_capacity() )
     {
-        cnode = table[crow];
-        if ( cnode )
-        {
-            HashNode* n = cnode;
-            update_cnode();
-            return n;
-        }
-    }
-
-    return nullptr;
-}
-
-HashNode* XHash::find_next_node()
-{
-    HashNode* n = cnode;
-    if ( !n )
-        return nullptr;
-
-    update_cnode();
+        if ( !delete_a_node() )
+            break;
 
-    return n;
-}
+        ++stats.memcap_deletes;
+        ++num_freed;
+    }
 
-void XHash::set_key_opcodes(hash_func hash_fcn, keycmp_func keycmp_fcn)
-{
-    hashfcn_set_keyops(hashfcn, hash_fcn, keycmp_fcn);
+    return ( mem_allocator->is_over_capacity() ) ? HASH_PENDING :  HASH_OK;
 }
 
 } // namespace snort
index d9ea5f7dfb1fa6c64a7f8a5162a7399eb5b774e5..2d0e2f36c37254b9047e445bcfa49d46c4f9d6d5 100644 (file)
 // generic hash table - stores and maps key + data pairs
 // (supports memcap and automatic memory recovery when out of memory)
 
-#include "utils/sfmemcap.h"
+#include "framework/counts.h"
 #include "main/snort_types.h"
+#include "utils/memcap_allocator.h"
 
-#include "hash_defs.h"
-#include "hashfcn.h"
+class HashLruCache;
 
 namespace snort
 {
+class HashKeyOperations;
+class HashNode;
+
+struct XHashStats
+{
+    PegCount nodes_created = 0;
+    PegCount memcap_prunes = 0;
+    PegCount memcap_deletes = 0;
+    PegCount release_recycles = 0;
+    PegCount release_deletes = 0;
+};
+
 class SO_PUBLIC XHash
 {
 public:
-    XHash(int nrows_, int keysize_, int datasize_, unsigned long memcap,
-        bool anr_enabled, Hash_FREE_FCN, Hash_FREE_FCN, bool recycle_nodes);
-    ~XHash();
-
-    int free_over_allocations(unsigned work_limit, unsigned* num_freed);
-    void clear();
+    XHash(int rows, int keysize);
+    XHash(int rows, int keysize, int datasize, unsigned long memcap);
+    virtual ~XHash();
 
     int insert(const void* key, void* data);
-    HashNode* get_node(const void* key);
-    HashNode* get_node_with_prune(const void* key, bool* prune_performed);
-    int release_node(void* key);
-    int release_node(HashNode* node);
-    int delete_anr_or_lru_node();
     HashNode* find_node(const void* key);
     HashNode* find_first_node();
     HashNode* find_next_node();
-    void* get_user_data(void* key);
+    void* get_user_data();
+    void* get_user_data(const void* key);
+    void release();
+    int release_node(const void* key);
+    int release_node(HashNode* node);
     void* get_mru_user_data();
     void* get_lru_user_data();
-    void set_key_opcodes(hash_func, keycmp_func);
+    bool delete_lru_node();
+    void clear_hash();
 
-    // Set the maximum nodes used in this hash table.
-    //  Specifying 0 is unlimited (or otherwise limited by memcap).
+    // set max hash nodes, 0 == no limit
     void set_max_nodes(int max)
     { max_nodes = max; }
 
-    unsigned get_node_count()
-    { return count; }
+    unsigned get_num_nodes()
+    { return num_nodes; }
 
-    unsigned get_anr_count()
-    { return anr_count; }
+    void set_memcap(unsigned long memcap)
+    { mem_allocator->set_mem_capacity(memcap); }
 
-    unsigned get_total_finds()
-    { return find_success + find_fail; }
+    unsigned long get_memcap()
+    { return mem_allocator->get_mem_capacity(); }
 
-    unsigned get_find_fails()
-    { return find_fail; }
+    unsigned long get_mem_used()
+    { return mem_allocator->get_mem_allocated(); }
 
-    unsigned get_find_successes()
-    { return find_success; }
+    const XHashStats& get_stats() const
+    { return stats; }
 
-    void set_memcap(unsigned long new_memcap)
-    { mc.memcap = new_memcap; }
+    virtual int tune_memory_resources(unsigned work_limit, unsigned& num_freed);
 
-    unsigned long get_memcap()
-    { return mc.memcap; }
+protected:
+    void initialize(HashKeyOperations*);
+    void initialize();
 
-    unsigned long get_mem_used()
-    { return mc.memused; }
+    void initialize_node (HashNode*, const void* key, void* data, int index);
+    HashNode* allocate_node(const void* key, void* data, int index);
+    HashNode* find_node_row(const void* key, int& rindex);
+    void link_node(HashNode*);
+    void unlink_node(HashNode*);
+    bool delete_a_node();
+    void save_free_node(HashNode*);
+    HashNode* get_free_node();
+    void delete_hash_table();
+
+    virtual bool is_node_recovery_ok(HashNode*)
+    { return true; }
 
-    const HashNode* get_cnode () const
-    { return cnode; }
+    virtual void free_user_data(HashNode*)
+    { }
 
-    int get_keysize () const
-    { return keysize; }
+    MemCapAllocator* mem_allocator = nullptr;
+    HashLruCache* lru_cache = nullptr;
+    unsigned nrows = 0;
+    unsigned keysize = 0;
+    unsigned num_nodes = 0;
+    bool recycle_nodes = true;
+    bool anr_enabled = true;
 
 private:
+    HashNode** table = nullptr;
+    HashKeyOperations* hashkey_ops = nullptr;
+    HashNode* cursor = nullptr;
+    HashNode* fhead = nullptr;
+    unsigned datasize = 0;
+    unsigned long mem_cap = 0;
+    unsigned max_nodes = 0;
+    unsigned crow = 0;
+    XHashStats stats;
+
+    void set_number_of_rows(int nrows);
+    void move_to_front(HashNode*);
+    bool delete_free_node();
+    HashNode* release_lru_node();
+    void update_cursor();
     void purge_free_list();
-    void save_free_node(HashNode* hnode);
-    HashNode* get_free_node();
-    void glink_node(HashNode* hnode);
-    void gunlink_node(HashNode* hnode);
-    void gmove_to_front(HashNode* hnode);
-    HashNode* gfind_first();
-    HashNode* gfind_next();
-    void link_node(HashNode* hnode);
-    void unlink_node(HashNode* hnode);
-    void move_to_front(HashNode* n);
-    HashNode* allocate_node();
-    HashNode* find_node_row(const void* key, int* rindex);
-    void update_cnode();
-    int delete_free_node();
-
-    HashFnc* hashfcn = nullptr;     // hash function
-    int keysize = 0;                // bytes in key, if <= 0 -> keys are strings - FIXIT-H does negative keysize work?
-    int datasize = 0;               // bytes in key, if == 0 -> user data
-    unsigned mem_allocated_per_entry = 0;
-    HashNode** table = nullptr;        // array of node ptr's */
-    unsigned nrows = 0;             // # rows int the hash table use a prime number 211, 9871
-    unsigned count = 0;             // total # nodes in table
-    unsigned crow = 0;              // findfirst/next row in table
-    HashNode* cnode = nullptr;     // find_[first|next] node ptr
-    int splay = 1;                  // whether to splay nodes with same hash bucket
-    unsigned max_nodes = 0;         // maximum # of nodes within a hash
-    MEMCAP mc;
-    unsigned find_fail = 0;
-    unsigned find_success = 0;
-
-    HashNode* ghead = nullptr;     // global - root of all nodes allocated in table
-    HashNode* gtail = nullptr;
-    HashNode* gnode = nullptr;     // gfirst/gnext node ptr */
-    HashNode* fhead = nullptr;     // list of free nodes, which are recycled
-    HashNode* ftail = nullptr;
-    bool recycle_nodes = false;     // recycle nodes...
-
-    // Automatic Node Recover (ANR): When number of nodes in hash is equal
-    // to max_nodes, remove the least recently used nodes and use it for
-    // the new node. anr_tries indicates # of ANR tries.*/
-    unsigned anr_tries = 0;
-    unsigned anr_count = 0;      // # ANR ops performed
-    bool anr_enabled = false;    // false = anr disable, true = anr enabled
-
-    Hash_FREE_FCN anr_free = nullptr;
-    Hash_FREE_FCN usr_free = nullptr;
 };
 
 } // namespace snort
index f2b87d3ac78337faa7a433594abfdd42b2382d3a..d806d7a3b6fbedc0a4161935ae2fd580fc848acd 100644 (file)
 #include <cassert>
 #include <cstring>
 
+#include "flow/flow_key.h"
+
 #include "hash_defs.h"
+#include "hash_key_operations.h"
+#include "hash_lru_cache.h"
 
 using namespace snort;
 
 //-------------------------------------------------------------------------
-// private stuff
+// public stuff
 //-------------------------------------------------------------------------
 
-static inline HashNode* s_node_alloc(int keysize)
-{
-    auto node = static_cast<HashNode*>(
-        ::operator new(sizeof(HashNode) + keysize));
-
-    *node = {};
-    return node;
-}
-
-static inline void s_node_free(HashNode* node)
-{ ::operator delete(node); }
-
-void ZHash::delete_free_list()
-{
-    if ( !fhead )
-        return;
-
-    HashNode* cur = fhead;
-
-    while ( cur )
-    {
-        fhead = cur->gnext;
-        s_node_free(cur);
-        cur = fhead;
-    }
-}
-
-void ZHash::save_free_node(HashNode* node)
-{
-    if ( fhead )
-    {
-        node->gprev = nullptr;
-        node->gnext = fhead;
-        fhead->gprev = node;
-        fhead = node;
-    }
-    else
-    {
-        node->gprev = nullptr;
-        node->gnext = nullptr;
-        fhead = node;
-    }
-}
-
-HashNode* ZHash::get_free_node()
-{
-    HashNode* node = fhead;
-
-    if ( fhead )
-    {
-        fhead = fhead->gnext;
-
-        if ( fhead )
-            fhead->gprev = nullptr;
-    }
-
-    return node;
-}
-
-void ZHash::glink_node(HashNode* node)
-{
-    if ( ghead )
-    {
-        node->gprev = nullptr;
-        node->gnext = ghead;
-        ghead->gprev = node;
-        ghead = node;
-    }
-    else
-    {
-        node->gprev = nullptr;
-        node->gnext = nullptr;
-        ghead = node;
-        gtail = node;
-    }
-}
-
-void ZHash::gunlink_node(HashNode* node)
-{
-    if ( cursor == node )
-        cursor = node->gprev;
-
-    if ( ghead == node )
-    {
-        ghead = ghead->gnext;
-        if ( ghead )
-            ghead->gprev = nullptr;
-    }
-
-    if ( node->gprev )
-        node->gprev->gnext = node->gnext;
-
-    if ( node->gnext )
-        node->gnext->gprev = node->gprev;
-
-    if ( gtail == node )
-        gtail = node->gprev;
-}
-
-void ZHash::link_node(HashNode* node)
-{
-    if ( table[node->rindex] )  // UNINITUSE
-    {
-        node->prev = nullptr;
-        node->next = table[node->rindex];
-        table[node->rindex]->prev = node;
-        table[node->rindex] = node;
-    }
-    else
-    {
-        node->prev = nullptr;
-        node->next = nullptr;
-        table[node->rindex] = node;  // UNINITUSE
-    }
-}
 
-void ZHash::unlink_node(HashNode* node)
+ZHash::ZHash(int rows, int key_len)
+    : XHash(rows, key_len)
 {
-    if ( node->prev )
-    {
-        node->prev->next = node->next;
-        if ( node->next )
-            node->next->prev = node->prev;
-    }
-    else if ( table[node->rindex] )
-    {
-        table[node->rindex] = table[node->rindex]->next;
-
-        if ( table[node->rindex] )
-            table[node->rindex]->prev = nullptr;
-    }
+    initialize(new FlowHashKeyOps(nrows));
+    anr_enabled = false;
 }
 
-void ZHash::move_to_front(HashNode* node)
+void* ZHash::get(const void* key)
 {
-    // move to front of row list
-    if ( table[node->rindex] != node )
-    {
-        unlink_node(node);
-        link_node(node);
-    }
-
-    // move to front of global list
-    if ( node != ghead )
-    {
-        gunlink_node(node);
-        glink_node(node);
-    }
-}
+    assert(key);
 
-HashNode* ZHash::find_node_row(const void* key, int& row)
-{
-    unsigned hashkey = hashfcn->hash_fcn(
-        hashfcn, (const unsigned char*)key, keysize);
-
-    // Modulus is slow; use a table size that is a power of 2.
-    int index = hashkey & (nrows - 1);
-    row = index;
-
-    for ( HashNode* node = table[index]; node; node = node->next )  // UNINITUSE
-    {
-        if ( hashfcn->keycmp_fcn(node->key, key, keysize) )
-        {
-            move_to_front(node);
-            find_success++;
-            return node;
-        }
-    }
-
-    find_fail++;
-    return nullptr;
-}
-
-//-------------------------------------------------------------------------
-// public stuff
-//-------------------------------------------------------------------------
-
-ZHash::ZHash(int rows, int keysz)
-    : keysize(keysz)
-{
-    // adjust rows to be power of 2
-    if ( rows > 0 )
-        nrows = hash_nearest_power_of_2(rows);
-    else
-        nrows = -rows;   // if negative use as is
+    int index;
+    HashNode* node = find_node_row(key, index);
+    if ( node )
+        return node->data;
 
-    table = new HashNode*[nrows]();
-    hashfcn = hashfcn_new(nrows);
+    node = get_free_node();
+    if ( !node )
+        return nullptr;
 
-    fhead = cursor = nullptr;
-    ghead = gtail = nullptr;
-    count = find_success = find_fail = 0;
+    memcpy(node->key, key, keysize);
+    node->rindex = index;
+    link_node(node);
+    lru_cache->insert(node);
+    num_nodes++;
+    return node->data;
 }
 
-ZHash::~ZHash()
+void* ZHash::remove()
 {
-    hashfcn_free(hashfcn);
-
-    for ( unsigned i = 0; i < nrows; ++i )
-    {
-        for ( HashNode* node = table[i]; node; )
-        {
-            HashNode* onode = node;
-            node = node->next;
-            s_node_free(onode);
-        }
-    }
+    HashNode* node = lru_cache->get_current_node();
+    assert(node);
+    void* pv = node->data;
 
-    delete[] table;
-    delete_free_list();
+    unlink_node(node);
+    lru_cache->remove_node(node);
+    num_nodes--;
+    mem_allocator->free(node);
+    return pv;
 }
 
 void* ZHash::push(void* p)
 {
-    auto node = s_node_alloc(keysize);
-
+    auto node = (HashNode*)mem_allocator->allocate();
     node->key = (char*)node + sizeof(HashNode);
     node->data = p;
-
     save_free_node(node);
     return node->key;
 }
@@ -262,137 +94,36 @@ void* ZHash::push(void* p)
 void* ZHash::pop()
 {
     HashNode* node = get_free_node();
-
     if ( !node )
         return nullptr;
 
     void* pv = node->data;
-    s_node_free(node);
+    mem_allocator->free(node);
 
     return pv;
 }
 
-void* ZHash::get(const void* key, bool *new_node)
+void* ZHash::lru_first()
 {
-    int row;
-    HashNode* node = find_node_row(key, row);
-
-    if ( node )
-        return node->data;
-
-    node = get_free_node();
-
-    if ( !node )
-        return nullptr;
-
-    memcpy(node->key, key, keysize);
-
-    node->rindex = row;
-    link_node (node);
-    glink_node(node);
-
-    count++;
-
-    if (new_node)
-        *new_node = true;
-
-    return node->data;
-}
-
-void* ZHash::find(const void* key)
-{
-    int row;
-    HashNode* node = find_node_row(key, row);
-
-    if ( node )
-        return node->data;
-
-    return nullptr;
+    HashNode* node = lru_cache->get_lru_node();
+    return node ? node->data : nullptr;
 }
 
-void* ZHash::first()
+void* ZHash::lru_next()
 {
-    cursor = gtail;
-    return cursor ? cursor->data : nullptr;
+    HashNode* node = lru_cache->get_next_lru_node();
+    return node ? node->data : nullptr;
 }
 
-void* ZHash::next()
+void* ZHash::lru_current()
 {
-    if ( !cursor )
-        return nullptr;
-
-    cursor = cursor->gprev;
-    return cursor ? cursor->data : nullptr;
-}
-
-void* ZHash::current()
-{
-    return cursor ? cursor->data : nullptr;
-}
-
-bool ZHash::touch()
-{
-    HashNode* node = cursor;
-
-    if ( !node )
-        return false;
-
-    cursor = cursor->gprev;
-
-    if ( node != ghead )
-    {
-        gunlink_node(node);
-        glink_node(node);
-        return true;
-    }
-    return false;
-}
-
-bool ZHash::move_to_free_list(HashNode* node)
-{
-    if ( !node )
-        return false;
-
-    unlink_node(node);
-    gunlink_node(node);
-    count--;
-    save_free_node(node);
-
-    return true;
-}
-
-bool ZHash::release()
-{
-    HashNode* node = cursor;
-    cursor = nullptr;
-    return move_to_free_list(node);
-}
-
-bool ZHash::release(const void* key)
-{
-    int row;
-    HashNode* node = find_node_row(key, row);
-    return move_to_free_list(node);
-}
-
-void* ZHash::remove(const void* key)
-{
-    void* pv = nullptr;
-    int row;
-    HashNode* node = find_node_row(key, row);
-    if ( node )
-    {
-        unlink_node(node);
-        gunlink_node(node);
-        count--;
-        pv = node->data;
-        s_node_free(node);
-    }
-
-    return pv;
+    HashNode* node = lru_cache->get_current_node();
+    return node ? node->data : nullptr;
 }
 
-void ZHash::set_key_opcodes(hash_func hash_fcn, keycmp_func keycmp_fcn)
+void ZHash::lru_touch()
 {
-    hashfcn_set_keyops(hashfcn, hash_fcn, keycmp_fcn);
+    HashNode* node = lru_cache->get_current_node();
+    assert(node);
+    lru_cache->touch(node);
 }
index 27584532bde3dc1573689345dfde9044bd74f037..f7c2370bcd710265c563d921a8a6c0067929b440 100644 (file)
 
 #include <cstddef>
 
-#include "hashfcn.h"
+#include "hash/xhash.h"
 
-namespace snort
-{
-struct HashNode;
-}
-
-class ZHash
+class ZHash : public snort::XHash
 {
 public:
     ZHash(int nrows, int keysize);
-    ~ZHash();
 
     ZHash(const ZHash&) = delete;
     ZHash& operator=(const ZHash&) = delete;
@@ -41,51 +35,13 @@ public:
     void* push(void* p);
     void* pop();
 
-    void* first();
-    void* next();
-    void* current();
-    bool touch();
-
-    void* find(const void* key);
-    void* get(const void* key, bool *new_node = nullptr);
-    bool release(const void* key);
-    bool release();
-    void* remove(const void* key);
-    void set_key_opcodes(hash_func, keycmp_func);
-
-    inline unsigned get_count()
-    { return count; }
-
-private:
-    snort::HashNode* get_free_node();
-    snort::HashNode* find_node_row(const void*, int&);
-
-    void glink_node(snort::HashNode*);
-    void gunlink_node(snort::HashNode*);
-
-    void link_node(snort::HashNode*);
-    void unlink_node(snort::HashNode*);
-
-    void delete_free_list();
-    void save_free_node(snort::HashNode*);
-
-    bool move_to_free_list(snort::HashNode*);
-    void move_to_front(snort::HashNode*);
-
-private:
-    HashFnc* hashfcn;
-    int keysize;
-    unsigned nrows;
-    unsigned count;
-
-    unsigned find_fail;
-    unsigned find_success;
+    void* get(const void* key);
+    void* remove();
 
-    snort::HashNode** table;
-    snort::HashNode* ghead;
-    snort::HashNode* gtail;
-    snort::HashNode* fhead;
-    snort::HashNode* cursor;
+    void* lru_first();
+    void* lru_next();
+    void* lru_current();
+    void lru_touch();
 };
 
 #endif
index 3aa0c676e3ae89314fdeb94e742e8ac076dd28e5..14e3824819f4c34d7af871711796b6063dc7cf6c 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler_defs.h"
 #include "protocols/packet.h"
 #include "protocols/tcp.h"
index c10ef9f96b81495a084c8f11111ecb4889cb6596..cb067e213a8cd8ce786006549ffd21eea3d4810e 100644 (file)
@@ -56,7 +56,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index aebd49263235f51da428a501add0009e64f1a83d..df31e3ef52df5a6e13489f16eae95c2b1f9aca9d 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "detection/detection_engine.h"
 #include "detection/treenodes.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
index 2a24f7808949f2642576297155f886fd68c77908..06b521beed6d6d54129979659fe90f692c6b8df6 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "utils/util_ber.h"
 
index 9cdae7563542fb2ff3571ce91dcc34e298d3c200..4d4765cdece634122b2257dc8daf8b36de1cfef1 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "utils/util_ber.h"
 
index a347f7ed356ab7903973a29e2815854cb8187578..0aa3053721bba5c450d6bac1445246274008e99b 100644 (file)
@@ -25,7 +25,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 
 using namespace snort;
index c55bbb3c4a6a99d8eba8d0caf74215945a277bf7..9213600c81dfc3dc48c05025a48e73672a3f2d89 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/endianness.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
index 65d58a1f2524147c911e3893ba846919b0266bb2..ea672a92ca9676d4a18c5f5258de7353e2649998 100644 (file)
@@ -81,7 +81,7 @@
 #include "framework/endianness.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 434495141ece21a3567971f44fa51d9cc4e866ba..00ce2dd1e12619e46992336d38d236100f75e360 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/endianness.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 5ba9bd3dbde4efcc5aa41c37242434cd71cc058d..2ad0b406e31fb5e2dfb29b40a19627937b64318e 100644 (file)
@@ -97,7 +97,7 @@
 #include "framework/endianness.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 3a39ecfc30fd9240a3a5dbaa0aec931e678a37ba..0830bbdecda10fb478876dfb625c5304741a497b 100644 (file)
@@ -26,7 +26,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "helpers/literal_search.h"
 #include "log/messages.h"
 #include "parser/parse_utils.h"
index d09b2adce88cf21cb9e397c8a7eba06368819b09..b17c8f893a3e2a37a340c394bb6f6f043d7abd2a 100644 (file)
@@ -41,7 +41,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 52f0f7e7f6934aca8363c01d64cde82102911824..14621adf8963b6d8e29c0a4853e2734c93613cec 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 61f762aac26bd545ce7e20e634e34d58e17d69f1..7797fcd5fb2c299e9e14b2259e75ded6b4af6706 100644 (file)
@@ -29,7 +29,7 @@
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 
 using namespace snort;
 
index bb83a5cbd37d1e9db3d3ead3e4d963e6b0ce9abb..b0453a83092978e48819b97b636b8d0fed25caac 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index ac71613c2a693daba78d9e055d5f601faa0e6368..789c44bbd87417a9be373d1b985ec50ec5bd1f43 100644 (file)
@@ -27,7 +27,7 @@
 #include "detection/treenodes.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 4205b3264d08ece27c7c3e58eaf4b478cba76822..5b6336fafab443a5bb185daf87c882ded8bdfd35 100644 (file)
@@ -46,7 +46,8 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "hash/ghash.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_defs.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "parser/mstring.h"
 #include "protocols/packet.h"
@@ -618,7 +619,7 @@ static FLOWBITS_OBJECT* getFlowBitItem(char* flowbitName, FLOWBITS_OP* flowbits,
         }
 
         int hstatus = flowbit_state->flowbits_hash->insert(flowbitName, flowbits_item);
-        if (hstatus != GHASH_OK)
+        if (hstatus != HASH_OK)
             ParseError("Could not add flowbits key (%s) to hash.",flowbitName);
     }
     flowbits_item->toggle = flowbit_state->flowbits_toggle;
@@ -811,7 +812,7 @@ static FLOWBITS_GRP* getFlowBitGroup(char* groupName, FlowBitState* flowbit_stat
         // new group defined, add (bitop set later once we know size)
         flowbits_grp = (FLOWBITS_GRP*)snort_calloc(sizeof(*flowbits_grp));
         int hstatus = flowbit_state->flowbits_grp_hash->insert(groupName, flowbits_grp);
-        if (hstatus != GHASH_OK)
+        if (hstatus != HASH_OK)
             ParseAbort("Could not add flowbits group (%s) to hash.\n",groupName);
 
         flowbit_state->flowbits_grp_count++;
index 10ae82ceec44caa42606c886a681ebbba4037dea..48a147d66756691790a12791755296837a2d68ab 100644 (file)
@@ -52,7 +52,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 614237daae4b57a6ce1e5094258be5b97f1204b3..e9b6f3e768d69730dd73a7446ad9e213faf0718c 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index db237d187f8bbe7bf0454897635dd58711fe47cc..b3b6f741ac10abc97f445148df96f6f7817d0359 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "hash/hashes.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "parser/parse_utils.h"
 #include "profiler/profiler.h"
index e7296e4adbae4f6a71f3fbc6f1c61a3783bee16a..a17ad72464682d3a6acf275820775c1273afd31d 100644 (file)
@@ -46,7 +46,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/icmp4.h"
 #include "protocols/icmp6.h"
index 4f56193e9446d2bdaa800b9800b1747a65a63123..d16d372f848aa57390140f3635c210858c5c153a 100644 (file)
@@ -46,7 +46,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/icmp4.h"
 #include "protocols/icmp6.h"
index e1b00daf02186f952e6d996959d1a3ec4287ab88..ac2f3b471408bb20da33ac623795ea690e7ec88c 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/icmp4.h"
 #include "protocols/packet.h"
index 32a72e292d42dd4260dcc701803c8ec879d400e1..09fcb78e5d189cb978a60cde4e1ae3de3592b698 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index d37f8eced895d2fb1ecbfdf693c6151c9b007604..c263d595ecf7ba46873920f741d3b3812442def5 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 4c80b430dc01bb9cff2e483f4a584637ac26df7f..48c0480d39d29439449d27afef46f692e6ebc329 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/ipv4_options.h"
 #include "protocols/packet.h"
index 0de1051a5077965284dc983cd85e9486506cdf4d..f391248914b82b27a66e486ea3e4eff92d81b742 100644 (file)
@@ -42,7 +42,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "parser/mstring.h"
 #include "profiler/profiler.h"
index 327b3cece4369537b449c5b99860d9ef6bff9732..eb65fa5517a492ecf89b9661ff1437fe8bc250d1 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/icmp4.h"
 #include "protocols/packet.h"
index 5018984db6ef4933b4aaca145ab1367fe6707c63..07f66e870280e3544ddfcf7787f6166e6b569a36 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/cursor.h"
 #include "framework/decode_data.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "helpers/chunk.h"
 #include "lua/lua.h"
 #include "log/messages.h"
index 5da5a8e3df8b357359aa9d4973ac7191311f6555..56f498996a555676a65a0c47d232accad9ebda4d 100644 (file)
@@ -31,7 +31,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/parameter.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "helpers/scratch_allocator.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
index 74be74f70bf042da38b869e2710c4275a671adc3..6159e5e230bc8c7cd17047a441a539bf09cf32d0 100644 (file)
@@ -32,7 +32,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "helpers/hyper_scratch_allocator.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
index 8c10b64d9f9f91d96124a2c188299e62a4dc66bc..50071f2ee35ddcaf935929594fd7f33b890b30b0 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
 #include "main/thread_config.h"
index 7fe436a2e136bdb020a60872d6ac13fd8f7e4e61..7c3f27eb9ac4e5385bc909e3d2cd1c3f5fc2406c 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 83f68b705bece91ce2a7090ad4c5800722001f8c..3a09e2ef92e3f66dd01d771a227f5f0ec8c5b442 100644 (file)
@@ -31,7 +31,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "helpers/hyper_scratch_allocator.h"
 #include "log/messages.h"
 #include "log/obfuscator.h"
index d3d145895822e04b9c804690198eb8ab9410578f..c70e8dbfaaca0fe93f9db6d201bc7bed9f1eaf42 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 #include "protocols/tcp.h"
index c86362ab4bda2a916ccb2723c0bb7239ba945403..598edbe46b008f3518daf12f410dc006d9f25bb8 100644 (file)
@@ -49,7 +49,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
 #include "profiler/profiler.h"
index 147b142fea4b5caef783e77c701e3f8a57fad032..f9470221089cbd58c87831f573825d8ba14145a6 100644 (file)
@@ -25,7 +25,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/so_rule.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "main/snort_config.h"
 #include "managers/so_manager.h"
index ddf32df9ccec32be680dc1218ae95b72f935d3f7..075eaa813fa6546c25b1eb8f46b6a1c555af1c49 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 93d7acb0ec594e7274bc5e113813592248a05649..c190aaa6e8ae9edfe2884164ef19807a3c26d95b 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index e0e1408483a4bfa818ae25a63778cf36f78d57e9..8b171137748a10e91d1e04710d80a80609224b82 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 #include "protocols/tcp.h"
index 6c5948f0516ad63ae60dd0cf278feaa403214f1d..c4c0ad476f66a8e8c0f26e333678bc81de0c6860 100644 (file)
@@ -27,8 +27,6 @@
 
 #include <cassert>
 #include <cstdarg>
-#include <cstdio>
-#include <cstring>
 
 #include "main/snort_config.h"
 #include "parser/parser.h"
@@ -43,6 +41,8 @@ static unsigned parse_errors = 0;
 static unsigned parse_warnings = 0;
 static unsigned reload_errors = 0;
 
+static std::string reload_errors_description;
+
 void reset_parse_errors()
 {
     parse_errors = 0;
@@ -63,11 +63,22 @@ unsigned get_parse_warnings()
     return tmp;
 }
 
+void reset_reload_errors()
+{
+    reload_errors = 0;
+    reload_errors_description.clear();
+}
+
 unsigned get_reload_errors()
 {
     return reload_errors;
 }
 
+std::string& get_reload_errors_description()
+{
+    return reload_errors_description;
+}
+
 static void log_message(FILE* file, const char* type, const char* msg)
 {
     const char* file_name;
@@ -125,12 +136,20 @@ void ReloadError(const char* format, ...)
     va_list ap;
 
     va_start(ap, format);
-    vsnprintf(buf, STD_BUF, format, ap);
+    vsnprintf(buf, sizeof(buf), format, ap);
     va_end(ap);
 
-    buf[STD_BUF] = '\0';
+    buf[sizeof(buf)-1] = '\0';
     log_message(stderr, "ERROR", buf);
 
+    if ( reload_errors_description.empty() )
+        reload_errors_description = buf;
+    else
+    {
+        reload_errors_description += ",";
+        reload_errors_description += buf;
+    }
+
     reload_errors++;
 }
 
index f830a4cbfb7df6429e4dab70cffcd7d30bf7fb85..316895d6dc4f6143a0e289672cd81739726df41a 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <arpa/inet.h>
 #include <cstdio>
+#include <string>
 #include <ctime>
 
 #include "main/snort_types.h"
@@ -49,7 +50,9 @@ enum WarningGroup
 void reset_parse_errors();
 unsigned get_parse_errors();
 unsigned get_parse_warnings();
+void reset_reload_errors();
 unsigned get_reload_errors();
+std::string& get_reload_errors_description();
 
 namespace snort
 {
index e8b1a3095697c905f92766898df3de7bb697fac5..f95e191b5c2d226ba3c798b6fe18f0a5f8bd6c1e 100644 (file)
@@ -351,7 +351,12 @@ int main_reload_config(lua_State* L)
     if ( !sc )
     {
         if (get_reload_errors())
-            current_request->respond("== reload failed - restart required\n");
+        {
+            std::string response_message = "== reload failed - restart required - ";
+            response_message += get_reload_errors_description() + "\n";
+            current_request->respond(response_message.c_str());
+            reset_reload_errors();
+        }
         else
             current_request->respond("== reload failed - bad config\n");
 
index a516f4cca80a48e04f26f5028a163b7d53c4fc7c..3fb2de0cf85a4c75c821ad2a24693ff0fd3c7c01 100644 (file)
@@ -498,160 +498,53 @@ void SnortConfig::merge(SnortConfig* cmd_line)
     state = new std::vector<void*>[num_slots];
 }
 
-// FIXIT-L this is a work around till snort supports adding/removing
-// stream cache during reload
-bool SnortConfig::verify_stream_inspectors()
-{
-    const std::vector<const char*> inspector_names
-        { "stream_file", "stream_icmp", "stream_ip", "stream_tcp", "stream_udp", "stream_user" };
-    static std::map <const char*, bool> orig_inspectors;
-
-    // If wasn't initialized before try to initialize from current config
-    if (orig_inspectors.empty())
-    {
-        const Inspector* const ptr = InspectorManager::get_inspector("stream", true);
-        if (ptr != nullptr)
-        {
-            for (auto name: inspector_names)
-            {
-                const bool in_orig = InspectorManager::inspector_exists_in_any_policy(name, get_conf());
-                orig_inspectors[name] = in_orig;
-            }
-        }
-    }
-
-    // If now available - compare
-    if (!orig_inspectors.empty())
-    {
-        const Inspector* const ptr = InspectorManager::get_inspector("stream", true, this);
-        if (ptr != nullptr)
-        {
-            for (auto name: inspector_names)
-            {
-                const bool in_new = InspectorManager::inspector_exists_in_any_policy(name, this);
-                if (orig_inspectors[name] != in_new)
-                {
-                    ReloadError("Snort Reload: Adding/removing %s requires a restart.\n", name);
-                    return false;
-                }
-            }
-        }
-    }
-
-    return true;
-}
-
 bool SnortConfig::verify()
 {
+    bool config_ok = false;
+
     if (get_conf()->asn1_mem != asn1_mem)
-    {
-        ReloadError("Snort Reload: Changing the asn1 memory configuration "
-            "requires a restart.\n");
-        return false;
-    }
+        ReloadError("Changing detection.asn1_mem requires a restart.\n");
 
-    if ( bpf_filter != get_conf()->bpf_filter )
-    {
-        ReloadError("Snort Reload: Changing the bpf filter configuration "
-            "requires a restart.\n");
-        return false;
-    }
+    else if ( get_conf()->bpf_filter != bpf_filter )
+        ReloadError("Changing packets.bfp_filter requires a restart.\n");
 
-    if ( respond_attempts != get_conf()->respond_attempts ||
-        respond_device != get_conf()->respond_device )
-    {
-        ReloadError("Snort Reload: Changing config response requires a restart.\n");
-        return false;
-    }
+    else if ( get_conf()->respond_attempts != respond_attempts )
+        ReloadError("Changing active.attempts requires a restart.\n");
 
-    if (get_conf()->chroot_dir != chroot_dir)
-    {
-        ReloadError("Snort Reload: Changing the chroot directory "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else if (  get_conf()->respond_device != respond_device )
+        ReloadError("Changing active.device requires a restart.\n");
 
-    if ((get_conf()->run_flags & RUN_FLAG__DAEMON) !=
-        (run_flags & RUN_FLAG__DAEMON))
-    {
-        ReloadError("Snort Reload: Changing to or from daemon mode "
-            "requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->chroot_dir != chroot_dir)
+        ReloadError("Changing process.chroot requires a restart.\n");
 
-    /* Orig log dir because a chroot might have changed it */
-    if (get_conf()->orig_log_dir != orig_log_dir)
-    {
-        ReloadError("Snort Reload: Changing the log directory "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else if ((get_conf()->run_flags & RUN_FLAG__DAEMON) != (run_flags & RUN_FLAG__DAEMON))
+        ReloadError("Changing process.daemon requires a restart.\n");
 
-    if (get_conf()->max_attribute_hosts != max_attribute_hosts)
-    {
-        ReloadError("Snort Reload: Changing max_attribute_hosts "
-            "configuration requires a restart.\n");
-        return false;
-    }
-    if (get_conf()->max_attribute_services_per_host != max_attribute_services_per_host)
-    {
-        ReloadError("Snort Reload: Changing max_attribute_services_per_host "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->orig_log_dir != orig_log_dir)
+        ReloadError("Changing output.logdir requires a restart.\n");
 
-    if ((get_conf()->run_flags & RUN_FLAG__NO_PROMISCUOUS) !=
-        (run_flags & RUN_FLAG__NO_PROMISCUOUS))
-    {
-        ReloadError("Snort Reload: Changing to or from promiscuous mode "
-            "requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->group_id != group_id)
+        ReloadError("Changing process.setgid requires a restart.\n");
 
-    if (get_conf()->group_id != group_id)
-    {
-        ReloadError("Snort Reload: Changing the group id configuration requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->user_id != user_id)
+        ReloadError("Changing process.setuid requires a restart.\n");
 
-    if (get_conf()->user_id != user_id)
-    {
-        ReloadError("Snort Reload: Changing the user id configuration requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->daq_config->get_mru_size() != daq_config->get_mru_size())
+        ReloadError("Changing daq.snaplen requires a restart.\n");
 
-    if (get_conf()->daq_config->get_mru_size() != daq_config->get_mru_size())
-    {
-        ReloadError("Snort Reload: Changing the packet snaplen "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->threshold_config->memcap != threshold_config->memcap)
+        ReloadError("Changing alerts.event_filter_memcap requires a restart.\n");
 
-    if (get_conf()->threshold_config->memcap !=
-        threshold_config->memcap)
-    {
-        ReloadError("Snort Reload: Changing the threshold memcap "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else  if (get_conf()->rate_filter_config->memcap != rate_filter_config->memcap)
+        ReloadError("Changing alerts.rate_filter_memcap requires a restart.\n");
 
-    if (get_conf()->rate_filter_config->memcap !=
-        rate_filter_config->memcap)
-    {
-        ReloadError("Snort Reload: Changing the rate filter memcap "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else if (get_conf()->detection_filter_config->memcap != detection_filter_config->memcap)
+        ReloadError("Changing alerts.detection_filter_memcap requires a restart.\n");
 
-    if (get_conf()->detection_filter_config->memcap !=
-        detection_filter_config->memcap)
-    {
-        ReloadError("Snort Reload: Changing the detection filter memcap "
-            "configuration requires a restart.\n");
-        return false;
-    }
+    else
+        config_ok = true;
 
-    return verify_stream_inspectors();
+    return config_ok;
 }
 
 void SnortConfig::set_alert_before_pass(bool enabled)
index af2b992f166638e93365d00169eed969e8272764..ce428f451554e20dcbc3406e4bab341adc7362a3 100644 (file)
@@ -41,7 +41,7 @@ enum RunFlag
 {
     RUN_FLAG__READ                = 0x00000001,
     RUN_FLAG__DAEMON              = 0x00000002,
-    RUN_FLAG__NO_PROMISCUOUS      = 0x00000004,
+    // unused                     = 0x00000004,
     // unused                     = 0x00000008,
 
     RUN_FLAG__INLINE              = 0x00000010,
@@ -149,8 +149,8 @@ struct VarNode;
 
 namespace snort
 {
-class ProtocolReference;
 class GHash;
+class ProtocolReference;
 class XHash;
 struct ProfilerConfig;
 struct SnortConfig;
@@ -181,7 +181,6 @@ struct SnortConfig
 {
 private:
     void init(const SnortConfig* const, ProtocolReference*);
-    bool verify_stream_inspectors();
 
 public:
     SnortConfig(const SnortConfig* const other_conf = nullptr);
index 7c962b6192c7c461703032b51205990f18de95b9..4cfcc4603f2a85da072438b56183bc5cff64f2b9 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "detection/detection_engine.h"
 #include "file_api/file_flows.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "search_engines/search_tool.h"
 #include "utils/util_cstring.h"
index ad8f530e33eca434db36fb95081ea0ab58fc7d7e..77a53b064d38b91116097960c85607e5324e8254 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 #include "utils/util.h"
index 85c5eb02c6338fd058216918b34e789feb57590d..9a4d0c5ac39124a6d66e1d87d73f8833e3f2db40 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "flow_ip_tracker.h"
 
+#include "hash/hash_defs.h"
 #include "log/messages.h"
 #include "protocols/packet.h"
 
@@ -46,9 +47,8 @@ FlowStateValue* FlowIPTracker::find_stats(const SfIp* src_addr, const SfIp* dst_
 {
     FlowStateKey key;
     FlowStateValue* value = nullptr;
-    bool prune_required = false;
 
-    if (src_addr->less_than(*dst_addr))
+    if ( src_addr->less_than(*dst_addr) )
     {
         key.ipA = *src_addr;
         key.ipB = *dst_addr;
@@ -62,21 +62,12 @@ FlowStateValue* FlowIPTracker::find_stats(const SfIp* src_addr, const SfIp* dst_
     }
 
     value = (FlowStateValue*)ip_map->get_user_data(&key);
-    if (!value)
+    if ( !value )
     {
-        HashNode* node = ip_map->get_node_with_prune(&key, &prune_required);
-
-        if (!node)
+        if ( ip_map->insert(&key, nullptr) != HASH_OK )
             return nullptr;
-
-        if (prune_required)
-        {
-            ++pmstats.total_frees;
-            ++pmstats.alloc_prunes;
-        }
-
-        memset(node->data, 0, sizeof(FlowStateValue));
-        value = (FlowStateValue*)node->data;
+        value = (FlowStateValue*)ip_map->get_user_data();
+        memset(value, 0, sizeof(FlowStateValue));
     }
 
     return value;
@@ -88,8 +79,8 @@ bool FlowIPTracker::initialize(size_t new_memcap)
 
     if ( !ip_map )
     {
-        ip_map = new XHash(DEFAULT_XHASH_NROWS, sizeof(FlowStateKey), sizeof(FlowStateValue),
-            new_memcap, true, nullptr, nullptr, true);
+        ip_map = new XHash(DEFAULT_XHASH_NROWS, sizeof(FlowStateKey),
+            sizeof(FlowStateValue), new_memcap);
     }
     else
     {
@@ -140,23 +131,25 @@ FlowIPTracker::FlowIPTracker(PerfConfig* perf) : PerfTracker(perf, TRACKER_NAME)
     formatter->finalize_fields();
 
     memcap = perf->flowip_memcap;
-    ip_map = new XHash(DEFAULT_XHASH_NROWS, sizeof(FlowStateKey), sizeof(FlowStateValue),
-        memcap, true, nullptr, nullptr, true);
+    ip_map = new XHash(DEFAULT_XHASH_NROWS, sizeof(FlowStateKey), sizeof(FlowStateValue), memcap);
 }
 
 FlowIPTracker::~FlowIPTracker()
 {
+    const XHashStats& stats = ip_map->get_stats();
+    pmstats.flow_tracker_creates = stats.nodes_created;
+    pmstats.flow_tracker_total_deletes = stats.memcap_deletes;
+    pmstats.flow_tracker_prunes = stats.memcap_prunes;
+
     delete ip_map;
 }
 
 void FlowIPTracker::reset()
-{
-    ip_map->clear();
-}
+{ ip_map->clear_hash(); }
 
 void FlowIPTracker::update(Packet* p)
 {
-    if (p->has_ip() && !p->is_rebuilt())
+    if ( p->has_ip() && !p->is_rebuilt() )
     {
         FlowType type = SFS_TYPE_OTHER;
         int swapped;
@@ -171,12 +164,12 @@ void FlowIPTracker::update(Packet* p)
             type = SFS_TYPE_UDP;
 
         FlowStateValue* value = find_stats(src_addr, dst_addr, &swapped);
-        if (!value)
+        if ( !value )
             return;
 
         TrafficStats* stats = &value->traffic_stats[type];
 
-        if (!swapped)
+        if ( !swapped )
         {
             stats->packets_a_to_b++;
             stats->bytes_a_to_b += len;
@@ -214,11 +207,10 @@ int FlowIPTracker::update_state(const SfIp* src_addr, const SfIp* dst_addr, Flow
     int swapped;
 
     FlowStateValue* value = find_stats(src_addr, dst_addr, &swapped);
-    if (!value)
+    if ( !value )
         return 1;
 
     value->state_changes[state]++;
-
     return 0;
 }
 
index 9df381e3b46b5a4b52b3aaeda6e3ad9105479bfc..8c038418f6a8e6831a5a895b9ba18aeb2cfa3ef3 100644 (file)
@@ -29,6 +29,7 @@
 #endif
 
 #include "framework/data_bus.h"
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "log/messages.h"
 #include "managers/inspector_manager.h"
@@ -270,9 +271,8 @@ bool PerfMonReloadTuner::tune_resources(unsigned work_limit)
     if (flow_ip_tracker)
     {
         unsigned num_freed = 0;
-        int result = flow_ip_tracker->get_ip_map()->free_over_allocations(work_limit, &num_freed);
-        pmstats.total_frees += num_freed;
-        pmstats.reload_frees += num_freed;
+        int result = flow_ip_tracker->get_ip_map()->tune_memory_resources(work_limit, num_freed);
+        pmstats.flow_tracker_reload_deletes += num_freed;
         return (result == HASH_OK);
     }
     else
index 26628b19876fdd70740561343993e9f86f2af4f0..8d503970dd28b8e91048dcff1f93aaf8b4fc0e7d 100644 (file)
 
 static const PegInfo perf_module_pegs[] =
 {
-
     { CountType::SUM, "packets", "total packets processed by performance monitor" },
-    { CountType::SUM, "total_frees", "total flows pruned or freed by performance monitor" },
-    { CountType::SUM, "reload_frees", "flows freed on reload with changed memcap" },
-    { CountType::SUM, "alloc_prunes", "flows pruned on allocation of IP flows" },
+    { CountType::SUM, "flow_tracker_creates", "total number of flow trackers created" },
+    { CountType::SUM, "flow_tracker_total_deletes", "flow trackers deleted to stay below memcap limit" },
+    { CountType::SUM, "flow_tracker_reload_deletes", "flow trackers deleted due to memcap change on config reload" },
+    { CountType::SUM, "flow_tracker_prunes", "flow trackers pruned for reuse by new flows" },
     { CountType::END, nullptr, nullptr },
 };
 
 struct PerfPegStats
 {
     PegCount total_packets;
-    PegCount total_frees;
-    PegCount reload_frees;
-    PegCount alloc_prunes;
+    PegCount flow_tracker_creates;
+    PegCount flow_tracker_total_deletes;
+    PegCount flow_tracker_reload_deletes;
+    PegCount flow_tracker_prunes;
 };
 
 #endif
index 4ee4800b3c0111f9ce6a177188297dce2afa1b22..693bb7a9f936a181ed4e696d8c303cb4c0bfe41e 100644 (file)
@@ -33,6 +33,7 @@
 
 #include "ps_detect.h"
 
+#include "hash/hash_defs.h"
 #include "hash/xhash.h"
 #include "log/messages.h"
 #include "protocols/icmp4.h"
@@ -57,7 +58,32 @@ struct PS_HASH_KEY
 };
 PADDING_GUARD_END
 
-static THREAD_LOCAL XHash* portscan_hash = nullptr;
+class PortScanCache : public XHash
+{
+public:
+    PortScanCache(unsigned rows, unsigned key_len, unsigned datasize, unsigned memcap)
+        : XHash(rows, key_len, datasize, memcap)
+    { }
+
+    bool is_node_recovery_ok(HashNode* hnode) override
+    {
+        PS_TRACKER* tracker = (PS_TRACKER*)hnode->data;
+
+        if ( !tracker->priority_node )
+            return true;
+
+        /*
+         **  Cycle through the protos to see if it's past the time.
+         **  We only get here if we ARE a priority node.
+         */
+        if ( tracker->proto.window >= packet_time() )
+            return false;
+
+        return true;
+    }
+};
+
+static THREAD_LOCAL PortScanCache* portscan_hash = nullptr;
 extern THREAD_LOCAL PsPegStats spstats;
 
 PS_PKT::PS_PKT(Packet* p)
@@ -84,32 +110,6 @@ PortscanConfig::~PortscanConfig()
         ipset_free(watch_ip);
 }
 
-/*
-**  This function is passed into the hash algorithm, so that
-**  we only reuse nodes that aren't priority nodes.  We have to make
-**  sure that we only track so many priority nodes, otherwise we could
-**  have all priority nodes and not be able to allocate more.
-*/
-static int ps_tracker_free(void* key, void* data)
-{
-    if (!key || !data)
-        return 0;
-
-    PS_TRACKER* tracker = (PS_TRACKER*)data;
-
-    if (!tracker->priority_node)
-        return 0;
-
-    /*
-    **  Cycle through the protos to see if it's past the time.
-    **  We only get here if we ARE a priority node.
-    */
-    if (tracker->proto.window >= packet_time())
-        return 1;
-
-    return 0;
-}
-
 void ps_cleanup()
 {
     if ( portscan_hash )
@@ -132,8 +132,8 @@ bool ps_init_hash(unsigned long memcap)
     }
 
     int rows = memcap / ps_node_size();
-    portscan_hash = new XHash(rows, sizeof(PS_HASH_KEY), sizeof(PS_TRACKER),
-        memcap, true, ps_tracker_free, nullptr, true);
+    portscan_hash = new PortScanCache(rows, sizeof(PS_HASH_KEY), sizeof(PS_TRACKER),
+        memcap);
 
     return false;
 }
@@ -144,7 +144,7 @@ bool ps_prune_hash(unsigned work_limit)
         return true;
 
     unsigned num_pruned = 0;
-    int result = portscan_hash->free_over_allocations(work_limit, &num_pruned);
+    int result = portscan_hash->tune_memory_resources(work_limit, num_pruned);
     spstats.reload_prunes += num_pruned;
     return result != HASH_PENDING;
 }
@@ -152,7 +152,7 @@ bool ps_prune_hash(unsigned work_limit)
 void ps_reset()
 {
     if ( portscan_hash )
-        portscan_hash->clear();
+        portscan_hash->clear_hash();
 }
 
 //  Check scanner and scanned ips to see if we can filter them out.
@@ -297,12 +297,12 @@ static PS_TRACKER* ps_tracker_get(PS_HASH_KEY* key)
     if ( ht )
         return ht;
 
-    auto prev_count = portscan_hash->get_node_count();
+    auto prev_count = portscan_hash->get_num_nodes();
     if ( portscan_hash->insert((void*)key, nullptr) != HASH_OK )
         return nullptr;
 
     ++spstats.trackers;
-    if ( prev_count == portscan_hash->get_node_count() )
+    if ( prev_count == portscan_hash->get_num_nodes() )
         ++spstats.alloc_prunes;
 
     ht = (PS_TRACKER*)portscan_hash->get_mru_user_data();
index 8dd5ef27e0b155d4f6f69c560209d105074ca3e0..05a7b299cb9f8e93bf497c6c0689d854581a1897 100644 (file)
@@ -34,7 +34,8 @@
 #include "filters/detection_filter.h"
 #include "filters/rate_filter.h"
 #include "filters/sfthreshold.h"
-#include "hash/hashfcn.h"
+#include "hash/ghash.h"
+#include "hash/hash_key_operations.h"
 #include "hash/xhash.h"
 #include "helpers/directory.h"
 #include "log/messages.h"
@@ -64,6 +65,62 @@ static struct rule_index_map_t* ruleIndexMap = nullptr;
 
 static std::string s_aux_rules;
 
+class RuleTreeHashKeyOps : public HashKeyOperations
+{
+public:
+    RuleTreeHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
+
+    unsigned do_hash(const unsigned char* k, int) override
+    {
+        uint32_t a,b,c;
+        const RuleTreeNodeKey* rtnk = (const RuleTreeNodeKey*)k;
+        RuleTreeNode* rtn = rtnk->rtn;
+
+        a = rtn->action;
+        b = rtn->flags;
+        c = (uint32_t)(uintptr_t)rtn->listhead;
+
+        mix(a,b,c);
+
+        a += (uint32_t)(uintptr_t)rtn->src_portobject;
+        b += (uint32_t)(uintptr_t)rtn->dst_portobject;
+        c += (uint32_t)(uintptr_t)rtnk->policyId;
+
+        finalize(a,b,c);
+
+        return c;
+    }
+
+    bool key_compare(const void* k1, const void* k2, size_t) override
+    {
+        assert(k1 && k2);
+
+        const RuleTreeNodeKey* rtnk1 = (const RuleTreeNodeKey*)k1;
+        const RuleTreeNodeKey* rtnk2 = (const RuleTreeNodeKey*)k2;
+
+        if (rtnk1->policyId != rtnk2->policyId)
+            return false;
+
+        if (same_headers(rtnk1->rtn, rtnk2->rtn))
+            return true;
+
+        return false;
+    }
+};
+
+class RuleTreeCache : public XHash
+{
+public:
+    RuleTreeCache(int rows, int key_len)
+        : XHash(rows, key_len)
+    {
+        initialize(new RuleTreeHashKeyOps(nrows));
+        anr_enabled = false;
+    }
+};
+
 //-------------------------------------------------------------------------
 // private / implementation methods
 //-------------------------------------------------------------------------
@@ -565,44 +622,6 @@ RuleTreeNode* deleteRtnFromOtn(OptTreeNode* otn, SnortConfig* sc)
     return deleteRtnFromOtn(otn, get_ips_policy()->policy_id, sc);
 }
 
-static uint32_t rtn_hash_func(HashFnc*, const unsigned char* k, int)
-{
-    uint32_t a,b,c;
-    const RuleTreeNodeKey* rtnk = (const RuleTreeNodeKey*)k;
-    RuleTreeNode* rtn = rtnk->rtn;
-
-    a = rtn->action;
-    b = rtn->flags;
-    c = (uint32_t)(uintptr_t)rtn->listhead;
-
-    mix(a,b,c);
-
-    a += (uint32_t)(uintptr_t)rtn->src_portobject;
-    b += (uint32_t)(uintptr_t)rtn->dst_portobject;
-    c += (uint32_t)(uintptr_t)rtnk->policyId;
-
-    finalize(a,b,c);
-
-    return c;
-}
-
-static bool rtn_compare_func(const void* k1, const void* k2, size_t)
-{
-    const RuleTreeNodeKey* rtnk1 = (const RuleTreeNodeKey*)k1;
-    const RuleTreeNodeKey* rtnk2 = (const RuleTreeNodeKey*)k2;
-
-    if (!rtnk1 || !rtnk2)
-        return false;
-
-    if (rtnk1->policyId != rtnk2->policyId)
-        return false;
-
-    if (same_headers(rtnk1->rtn, rtnk2->rtn))
-        return true;
-
-    return false;
-}
-
 int addRtnToOtn(SnortConfig* sc, OptTreeNode* otn, RuleTreeNode* rtn, PolicyId policyId)
 {
     if (otn->proto_node_num <= policyId)
@@ -627,7 +646,6 @@ int addRtnToOtn(SnortConfig* sc, OptTreeNode* otn, RuleTreeNode* rtn, PolicyId p
     }
 
     RuleTreeNode* curr = otn->proto_nodes[policyId];
-
     if ( curr )
     {
         deleteRtnFromOtn(otn, policyId, sc, (curr->otnRefCount == 1));
@@ -637,11 +655,7 @@ int addRtnToOtn(SnortConfig* sc, OptTreeNode* otn, RuleTreeNode* rtn, PolicyId p
     rtn->otnRefCount++;
 
     if (!sc->rtn_hash_table)
-    {
-        sc->rtn_hash_table = new XHash(
-            10000, sizeof(RuleTreeNodeKey), 0, 0, false, nullptr, nullptr, true);
-        sc->rtn_hash_table->set_key_opcodes(rtn_hash_func, rtn_compare_func);
-    }
+        sc->rtn_hash_table = new RuleTreeCache(10000, sizeof(RuleTreeNodeKey));
 
     RuleTreeNodeKey key;
     memset(&key, 0, sizeof(key));
index 5e6114e3da723be52abfd433b7af367beafdccb6..50d424cab7a239203d0d753ac761372847298ae0 100644 (file)
@@ -287,7 +287,7 @@ int PortObjectNormalize(PortObject* po)
 /*
    PortObjects should be normalized, prior to testing
 */
-int PortObjectEqual(PortObject* a, PortObject* b)
+bool PortObjectEqual(PortObject* a, PortObject* b)
 {
     PortObjectItem* pa;
     PortObjectItem* pb;
@@ -295,7 +295,7 @@ int PortObjectEqual(PortObject* a, PortObject* b)
     SF_LNODE* posb;
 
     if ( a->item_list->count != b->item_list->count )
-        return 0;
+        return false;
 
     pa = (PortObjectItem*)sflist_first(a->item_list,&posa);
     pb = (PortObjectItem*)sflist_first(b->item_list,&posb);
@@ -303,16 +303,16 @@ int PortObjectEqual(PortObject* a, PortObject* b)
     while ( pa && pb )
     {
         if ( !PortObjectItemsEqual(pa, pb) )
-            return 0;
+            return false;
 
         pa = (PortObjectItem*)sflist_next(&posa);
         pb = (PortObjectItem*)sflist_next(&posb);
     }
 
     if ( pa || pb ) /* both are not done - cannot match */
-        return 0;
+        return false;
 
-    return 1; /* match */
+    return true; /* match */
 }
 
 /*
index f4e68174f113ac2a9f7d7f2b58bc4263dacd694b..3847ab4a42a5b98c490d2b82349ebe7c4afdc248 100644 (file)
@@ -61,7 +61,7 @@ PortObject* PortObjectDupPorts(PortObject*);
 
 int PortObjectNormalize(PortObject*);
 void PortObjectToggle(PortObject*);
-int PortObjectEqual(PortObject* poa, PortObject* pob);
+bool PortObjectEqual(PortObject* poa, PortObject* pob);
 
 int PortObjectPortCount(PortObject*);
 int PortObjectHasPort(PortObject*, int port);
index 090dd74303859c8161b1f3694f8b2ebece70fecd..fd801521f4c4a406a735213fdaddf976ef35644a 100644 (file)
@@ -23,7 +23,9 @@
 
 #include "port_object2.h"
 
-#include "hash/hashfcn.h"
+#include "hash/ghash.h"
+#include "hash/hash_defs.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "parser/parser.h"
 #include "utils/util.h"
@@ -55,21 +57,29 @@ using namespace snort;
 #define SWAP_BYTES(a)
 #endif
 
-static unsigned po_rule_hash_func(HashFnc* p, const unsigned char* k, int n)
+class PortObject2HashKeyOps : public HashKeyOperations
 {
-    unsigned char* key;
-    int ikey = *(const int*)k;
+public:
+    PortObject2HashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
 
-    /* Since the input is really an int, put the bytes into a normalized
-     * order so that the hash function returns consistent results across
-     * on BE & LE hardware. */
-    SWAP_BYTES(ikey);
+    unsigned do_hash(const unsigned char* k, int len) override
+    {
+        unsigned char* key;
+        int ikey = *(const int*)k;
 
-    /* Set a pointer to the key to pass to the hashing function */
-    key = (unsigned char*)&ikey;
+        /* Since the input is really an int, put the bytes into a normalized
+         * order so that the hash function returns consistent results across
+         * on BE & LE hardware. */
+        SWAP_BYTES(ikey);
 
-    return hashfcn_hash(p, key, n);
-}
+        /* Set a pointer to the key to pass to the hashing function */
+        key = (unsigned char*)&ikey;
+
+        return HashKeyOperations::do_hash(key, len);
+    }
+};
 
 static int* RuleHashToSortedArray(GHash* rh)
 {
@@ -92,14 +102,6 @@ static int* RuleHashToSortedArray(GHash* rh)
     return ra;
 }
 
-static bool port_object_key_compare_func(const void* k1, const void* k2, size_t len)
-{
-    if ( memcmp(k1, k2, len ) )
-        return false;
-    else
-        return true;
-}
-
 //-------------------------------------------------------------------------
 // PortObject2 - public
 //-------------------------------------------------------------------------
@@ -109,9 +111,7 @@ PortObject2* PortObject2New(int nrules)
     PortObject2* po = (PortObject2*)snort_calloc(sizeof(PortObject2));
     po->item_list = sflist_new();
     po->rule_hash = new GHash(nrules, sizeof(int), 0, snort_free);
-
-    /* Use hash function defined above for hashing the key as an int. */
-    po->rule_hash->set_key_opcodes(po_rule_hash_func, port_object_key_compare_func);
+    po->rule_hash->set_hashkey_ops(new PortObject2HashKeyOps(nrules));
 
     return po;
 }
@@ -189,7 +189,7 @@ PortObject2* PortObject2Dup(PortObject& po)
             int* prule = (int*)snort_calloc(sizeof(int));
             *prule = *prid;
 
-            if ( ponew->rule_hash->insert(prule, prule) != GHASH_OK )
+            if ( ponew->rule_hash->insert(prule, prule) != HASH_OK )
                 snort_free(prule);
         }
     }
@@ -226,7 +226,7 @@ PortObject2* PortObject2AppendPortObject(PortObject2* poa, PortObject* pob)
         int* prid2 = (int*)snort_calloc(sizeof(int));
         *prid2 = *prid;
 
-        if ( poa->rule_hash->insert(prid2, prid2) != GHASH_OK )
+        if ( poa->rule_hash->insert(prid2, prid2) != HASH_OK )
             snort_free(prid2);
     }
     return poa;
@@ -247,7 +247,7 @@ PortObject2* PortObject2AppendPortObject2(PortObject2* poa, PortObject2* pob)
         int* prid2 = (int*)snort_calloc(sizeof(int));
         *prid2 = *prid;
 
-        if ( poa->rule_hash->insert(prid2, prid2) != GHASH_OK )
+        if ( poa->rule_hash->insert(prid2, prid2) != HASH_OK )
             snort_free(prid2);
     }
     return poa;
index e95cccf2251ac27fb1097ba5ca68c4fc5d7756ce..67bafcb3c22241b69097610d5bac77650b2d4cbd 100644 (file)
 #define PORT_OBJECT2_H
 
 #include "framework/bits.h"
-#include "hash/ghash.h"
 #include "utils/sflsq.h"
 
 //-------------------------------------------------------------------------
 // PortObject2 is similar to PortObject
 //-------------------------------------------------------------------------
 
+namespace snort
+{
+class GHash;
+}
 
 struct PortObject;
 
index 71e30bf0e35a527eda1fb84d2ff34c2f35f58e03..26bd6a773c02ddac0885fa60a5ca7b56dc13dcc1 100644 (file)
@@ -25,7 +25,9 @@
 
 #include <memory>
 
-#include "hash/hashfcn.h"
+#include "hash/ghash.h"
+#include "hash/hash_defs.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "main/snort_debug.h"
 #include "utils/util.h"
@@ -77,24 +79,6 @@ static void plx_free(void* p)
     snort_free(p);
 }
 
-static unsigned plx_hash(HashFnc* p, const unsigned char* d, int)
-{
-    unsigned hash = p->seed;
-    const plx_t* plx = *(plx_t* const*)d;
-
-    for ( int i = 0; i < plx->n; i++ )
-    {
-        unsigned char* pc_ptr = (unsigned char*)&plx->p[i];
-
-        for ( unsigned k = 0; k < sizeof(void*); k++ )
-        {
-            hash *=  p->scale;
-            hash +=  pc_ptr[k];
-        }
-    }
-    return hash ^ p->hardener;
-}
-
 /* for sorting an array of pointers */
 static inline int p_keycmp(const void* a, const void* b)
 {
@@ -107,84 +91,93 @@ static inline int p_keycmp(const void* a, const void* b)
     return 0; /* they are equal */
 }
 
-/*
-   Hash Key Comparisons for treating plx_t types as Keys
-
-   return values memcmp style
-
-   this only needs to produce 0 => exact match, otherwise not.
-   -1, and +1 are not strictly needed, they could both return
-   a non zero value for the purposes of hashing and searching.
-*/
-static bool plx_keycmp(const void* a, const void* b, size_t)
+class PlxHashKeyOps : public HashKeyOperations
 {
-    const plx_t* pla = *(plx_t* const*)a;
-    const plx_t* plb = *(plx_t* const*)b;
+public:
+    PlxHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
 
-    if ( pla->n < plb->n )
-        return false;
+    unsigned do_hash(const unsigned char* k, int) override
+    {
+        unsigned hash = seed;
+        const plx_t* plx = *(plx_t* const*)k;
+
+        for ( int i = 0; i < plx->n; i++ )
+        {
+            unsigned char* pc_ptr = (unsigned char*)&plx->p[i];
 
-    if ( pla->n > plb->n )
-        return false;
+            for ( unsigned k = 0; k < sizeof(void*); k++ )
+            {
+                hash *=  scale;
+                hash +=  pc_ptr[k];
+            }
+        }
+        return hash ^ hardener;
+    }
 
-    for ( int i = 0; i < pla->n; i++ )
+    bool key_compare(const void* k1, const void* k2, size_t) override
     {
-        if ( p_keycmp(&pla->p[i], &plb->p[i]) )
+        const plx_t* pla = *(plx_t* const*)k1;
+        const plx_t* plb = *(plx_t* const*)k2;
+
+        if ( pla->n < plb->n )
             return false;
-    }
 
-    return true; /* they are equal */
-}
+        if ( pla->n > plb->n )
+            return false;
+
+        for ( int i = 0; i < pla->n; i++ )
+        {
+            if ( p_keycmp(&pla->p[i], &plb->p[i]) )
+                return false;
+        }
+
+        return true; /* they are equal */    }
+};
 
 //-------------------------------------------------------------------------
 // PortTable - private - other
 //-------------------------------------------------------------------------
 
-/*
-   Hash Key Comparisons for treating PortObjects as Keys
-
-   return values memcmp style
-*/
-static bool PortObject_keycmp(const void* a, const void* b, size_t)
+class PortObjectHashKeyOps : public HashKeyOperations
 {
-    return PortObjectEqual(*(PortObject* const*)a, *(PortObject* const*)b);
-}
-
-/*
-    Hash routine for hashing PortObjects as Keys
+public:
+    PortObjectHashKeyOps(int rows)
+        : HashKeyOperations(rows)
+    { }
 
-    p - HashFnc *
-    d - PortObject *
-    n = 4 bytes (sizeof*) - not used
+    unsigned do_hash(const unsigned char* k, int) override
+    {
+        unsigned hash = seed;
+        const PortObject* po = *(PortObject* const*)k;
+        SF_LNODE* pos;
 
-   Don't use this for type=ANY port objects
-*/
-static unsigned PortObject_hash(HashFnc* p, const unsigned char* d, int)
-{
-    unsigned hash = p->seed;
-    const PortObject* po = *(PortObject* const*)d;
-    SF_LNODE* pos;
+        for (PortObjectItem* poi = (PortObjectItem*)sflist_first(po->item_list, &pos);
+             poi != nullptr;
+             poi = (PortObjectItem*)sflist_next(&pos) )
+        {
+            if ( poi->any() )
+                continue;
 
-    /* hash up each item */
-    for (PortObjectItem* poi = (PortObjectItem*)sflist_first(po->item_list, &pos);
-         poi != nullptr;
-         poi = (PortObjectItem*)sflist_next(&pos) )
-    {
-        if ( poi->any() )
-            continue;
+            hash *= scale;
+            hash += poi->lport & 0xff;
+            hash *= scale;
+            hash += (poi->lport >> 8) & 0xff;
 
-        hash *=  p->scale;
-        hash +=  poi->lport & 0xff;
-        hash *=  p->scale;
-        hash +=  (poi->lport >> 8) & 0xff;
+            hash *= scale;
+            hash += poi->hport & 0xff;
+            hash *= scale;
+            hash += (poi->hport >> 8) & 0xff;
+        }
+        return hash ^ hardener;
+    }
 
-        hash *=  p->scale;
-        hash +=  poi->hport & 0xff;
-        hash *=  p->scale;
-        hash +=  (poi->hport >> 8) & 0xff;
+    bool key_compare(const void* k1, const void* k2, size_t) override
+    {
+        return PortObjectEqual(*(PortObject* const*)k1, *(PortObject* const*)k2);
     }
-    return hash ^ p->hardener;
-}
+};
 
 /*
  * Merge multiple PortObjects into a final PortObject2,
@@ -248,7 +241,7 @@ static PortObject2* _merge_N_pol(
     // Add the Merged PortObject2 to the PortObject2 hash table keyed by ports.
     int stat = mhash->insert(&ponew, ponew);
     // This is possible since PLX hash on a different key
-    if ( stat == GHASH_INTABLE )
+    if ( stat == HASH_INTABLE )
     {
         PortObject2* pox = (PortObject2*)mhash->find(&ponew);
         assert( pox );
@@ -264,7 +257,7 @@ static PortObject2* _merge_N_pol(
 
     // Add the plx node to the PLX hash table
     stat = mhashx->insert(&plx_tmp, ponew);
-    if ( stat == GHASH_INTABLE )
+    if ( stat == HASH_INTABLE )
         FatalError("Could not add merged plx to PLX HASH table-INTABLE\n");
 
     return ponew;
@@ -460,13 +453,12 @@ static void PortTableCompileMergePortObjects(PortTable* p)
 
     // Create a Merged Port Object Table - hash by ports, no user keys, don't free data
     GHash* mhash = new GHash(PO_HASH_TBL_ROWS, sizeof(PortObject*), 0, nullptr);
-
-    mhash->set_key_opcodes(PortObject_hash, PortObject_keycmp);
+    mhash->set_hashkey_ops(new PortObjectHashKeyOps(PO_HASH_TBL_ROWS));
     p->pt_mpo_hash = mhash;
 
     // Create a Merged Port Object Table - hash by pointers, no user keys, don't free data
     GHash* mhashx = new GHash(PO_HASH_TBL_ROWS, sizeof(plx_t*), 0, nullptr);
-    mhashx->set_key_opcodes(plx_hash, plx_keycmp);
+    mhashx->set_hashkey_ops(new PlxHashKeyOps(PO_HASH_TBL_ROWS));
 
     p->pt_mpxo_hash = mhashx;
     SF_LIST* plx_list = sflist_new();
index f12fd322a5d4952917a66c8fb3dac96cb957d655..6048c9c221333c2ff2ada0d2497717333137a21f 100644 (file)
 #ifndef PORT_TABLE_H
 #define PORT_TABLE_H
 
-#include "hash/ghash.h"
 #include "ports/port_item.h"
 #include "ports/port_object.h"
 #include "ports/port_object2.h"
 #include "utils/sflsq.h"
 
+namespace snort
+{
+class GHash;
+}
+
 //-------------------------------------------------------------------------
 // PortTable - provides support to analyze the Port List objects defined by
 // the user as either PortVar entries or simply as inline rule port list
index ea5257ecb69cc6312b3b12f46ea5a3489e60e66e..89ed38436c3536c446b049e777cc3cc5b4017b81 100644 (file)
@@ -23,6 +23,9 @@
 
 #include "port_var_table.h"
 
+#include "hash/ghash.h"
+#include "hash/hash_defs.h"
+
 using namespace snort;
 
 //-------------------------------------------------------------------------
@@ -72,10 +75,10 @@ int PortVarTableFree(PortVarTable* pvt)
 int PortVarTableAdd(PortVarTable* h, PortObject* po)
 {
     int stat = h->insert(po->name, po);
-    if ( stat == GHASH_INTABLE )
+    if ( stat == HASH_INTABLE )
         return 1;
 
-    if ( stat == GHASH_OK )
+    if ( stat == HASH_OK )
         return 0;
 
     return -1;
index 8aedbc6b243adf28ae1e17d8a4f79ce6fa8bf86c..7babca35d6bdd1d24e85adce3eb9480946951ee8 100644 (file)
 #ifndef PORT_VAR_TABLE_H
 #define PORT_VAR_TABLE_H
 
-#include "hash/ghash.h"
 #include "ports/port_object.h"
 #include "ports/port_table.h"
 
+namespace snort
+{
+class GHash;
+}
+
 //-------------------------------------------------------------------------
 // PortVarTable
 // port lists may be defined as 'name port-list'
index ada9362ade153d292b46e1c0fb525db389b092a2..c9ff7af1439e69e235d4c1d14aa578311cf82017 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index f7681414a09c8954cad18f1b3c7eae47d92856e1..c5a1d1f1671197b50ad6498aaa4fd1f260c8b78a 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 22e9a10f0eb4544523bd72698b4d473340c382ff..8f93c51593d0ebd0ed085ba33f4a19a853657921 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index c02260fd36c578fe6fcc307ce0552d12cdab637c..5dd433a739618e514e17c1e8a3b9dceefe385e9f 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index a1866fa6cc1a7b3f44be952e709b6d2eb5ac1053..f6dc0913bc11346af5fc9d3bc0c409988c2c1af4 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 64d249df234a347a387c264a0baa3d1d47fea295..d4659b0f3f04660eec29a14f030165811f626509 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index de93fb00514873c1027beb1358a27ebab0eadd86..36dc97fe1e309d00cf5d184b0e355b7699158054 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index bc78481bc7db033cddddac7882c133fae479c206..7fbea0cd36381be0a70e715b38161cfdec4a7f9d 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 8bed0e85c182522e6497d2648979b809f7ab4eca..a2c24b00eb9613a34ce1dae421c6a9d0fb82ba3b 100644 (file)
@@ -27,7 +27,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index cff11df7a79ba16f6aa2dee726004076c61dc1f3..55c7c17b7eb5b9ca551058952eb5fbdec0a9c1fc 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index a9036affa6b8a543674549452cc89a44eb0201c4..78517c215f786fef548bed0e8a85374a18f3f82b 100644 (file)
@@ -28,7 +28,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 701d1f2ab5982895a5700bdc5184a29ee9897e46..553fe42125779eeda1847c9324d416baaaacbf09 100644 (file)
@@ -29,7 +29,7 @@
 #include "framework/module.h"
 #include "framework/ips_option.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "target_based/snort_protocols.h"
 #include "utils/util.h"
index 11e675960fa549248fc0f0454dd77e296018b0d1..8e74d1d1961961ee3339c710645c91e626cca4fc 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "utils/util.h"
 
index 2f29d382eb39dec5858a54e5cd5fffef8a86b820..522b98ccc562c70fee295452d0900c26e204cf69 100644 (file)
@@ -26,7 +26,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 
 #include "dce_common.h"
index adebb878d64b79cfb3d13c2ffc253245e88af029..7d331678200c18b5d68b447c2d01cf06c2b7354b 100644 (file)
@@ -26,7 +26,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index 480c97fc510da7003bf52f33fccf3bf5c687e3c5..63a368308b2abc39b0d76b09ebcd82e4c5e52c7d 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 311d0988f2f5ed87bbeda4b846e9bf0b75890491..1549eefe9e8398b279c59af404da3d736531c014 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 26b158ea8970bc8c836789a009d42adb82a0ff45..eee61eaf2d7e431c8e906cd4dad7539276ec482c 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index fbd3747aec1a0e87c325053745eae77fefaa0573..1a35c2bf24577d059211b9bfd9d33759e0fceadd 100644 (file)
@@ -42,7 +42,7 @@
 
 #include "detection/detection_engine.h"
 #include "detection/detection_util.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "file_api/file_service.h"
 #include "protocols/packet.h"
 #include "stream/stream.h"
index f1d26e64815d0c735fd8d51d2775afdc183bf80d..6ba0373aaa8d78b8ef03c9a4b6c65f61650e160d 100644 (file)
@@ -24,7 +24,7 @@
 
 // gtp_info rule option implementation
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
index 5620fc18dee39f7809af1405e256e7b75531cca8..2c2dd6864753369b9d9a37f8ce58b42e6c1e090b 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index aaa5831da1d81f3e09c98873f42218d882ba4fc2..eca531c30903dd9e5fdd1d3768a12a0ca969aeeb 100644 (file)
@@ -26,7 +26,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index 1ab7e167622ecbb6c6be5e905ac9a8132783bb37..043ff0eaa3a9d1041b52187edefbfdd5de62de42 100644 (file)
@@ -20,7 +20,7 @@
 /* 
  * The purpose of this Packet subclass is to enable H2I to take direction from http_inspect on
  * whether or not to send a frame to detection. When http_inspect is processing normal HTTP/1.1
- * traffic it is dealing with a 'real' packet that has a context, the field on which disable_all()
+ * traffic it is dealing with a real packet that has a context, the field on which disable_all()
  * is called to disable detection on that packet. With HTTP/2 traffic, http_inspect is processing a
  * dummy packet that H2I created, which does not contain a context object. Rather than create an
  * entire new context object when we really only need a bool, http_inspect checks if the flow is
index e72f672d1f6f3edbc4b7fd59cbc9496bd896256f..0876a08aeaae95057e10fb14245c004f0ee25289 100644 (file)
@@ -17,7 +17,7 @@
 //--------------------------------------------------------------------------
 // http_buffer_info.cc author Brandon Stultz <brastult@cisco.com>
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "http_buffer_info.h"
 
 using namespace snort;
index 1ad11463e5e74fa3333835055507492e5a2ec7b5..f05d2556d0a9ce5d4c777f08557ded2f50c896ed 100644 (file)
@@ -32,7 +32,7 @@
 #include "http_msg_status.h"
 #include "http_msg_trailer.h"
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 
 using namespace HttpCommon;
 using namespace HttpEnums;
index 64c0c2e7869aa129d2d54032dd11f87cdedab0dd..c72480de3417253d44f6b29f83ca7034103be4cc 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "http_common.h"
 #include "http_enum.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 
 using namespace HttpCommon;
 using namespace HttpEnums;
index 1859f37e3dbb9493ed43f714343b1762a2a22657..67b602206bceb28d5c7931895ce10186073fa17a 100644 (file)
@@ -24,7 +24,7 @@
 #include "ips_http.h"
 
 #include "framework/cursor.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "parser/parse_utils.h"
 #include "protocols/packet.h"
index c7fe71ba0ec95278b2d1d7d7de75857860d520e0..2cf071522cb39d942882aca25741dc56ed4db9be 100644 (file)
@@ -26,7 +26,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index bfdde4114ace0513a53173e9fc5c5dcc51e46974..e564c99a890c980a4107e0ef9656feda5b9bde8e 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index 5ebf0416a2e147af96208bb11db7b221ffc58e84..076637083ce28124cb6e39d99e1a977a2dd54c81 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index 740cb90c4fa17f0b29aef1e0d2cbec58625b3b32..c17b7c54d7f0a73e2fa6dae2ad1533d63ae29632 100644 (file)
@@ -26,7 +26,7 @@
 #include "framework/cursor.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 
index 1a5da45c5031021d02b4a91edb1708e23871adaf..aaba91329eeb70a4b7726aadc1a1f0cc8527248b 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index d089ce5db771bd01749a4cf744f94b0f92e82d59..48478d549cacd52cb1f99e2bea07e99328926d43 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "protocols/packet.h"
 #include "profiler/profiler.h"
 
index 5382e05f5d250e574dcd93d1f7b1ac4223902b8a..f7bad4e019bbd70c26ca5bcf9f31afc9a2394db4 100644 (file)
@@ -30,7 +30,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index 04044b14583cedf5b8cc928c269930f2cc5039c2..45ae386b9a8396895bc599c7b40b1d99b9dd7df1 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "log/messages.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
index b2f85e5ed66f80ecea395e3923216141804add31..cf058ee4ee74d07b53d042b5ebf5c9cf904e8554 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <cstring>
 
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 
 /*
  * Trim spaces non-destructively on both sides of string : '', \t, \n, \r
index 98a1ba0c9c5c7c68aa4f2e881b7c20cb6d95abcd..a5db4ac5e3954165a0dc4355d68105a45b553b49 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 #include "protocols/ssl.h"
index 69bea2ad7ce7a7da35cff10651c82cec4501a874..2f846c9ea152d2468633a11241ae7242361adfff 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler.h"
 #include "protocols/packet.h"
 #include "protocols/ssl.h"
index eae32bd43c89c0718d431d87e359b03ac9364906..5e2a9e9710f35f220ef6f7b013f60110be3e0148 100644 (file)
@@ -194,7 +194,11 @@ void StreamBase::tinit()
     if ( config.flow_cache_cfg.max_flows > 0 )
         flow_con->init_exp(config.flow_cache_cfg.max_flows);
 
+#ifdef REG_TEST
     FlushBucket::set(config.footprint);
+#else
+    FlushBucket::set();
+#endif
 }
 
 void StreamBase::tterm()
index c8ba5a7c9d0888711023811dc23f01cc4b6713c3..56e5cf5d056184dff3feab2ddbbddf520342ce8a 100644 (file)
@@ -64,8 +64,10 @@ FLOW_TYPE_PARAMS(file_params, "180", "32");
 
 static const Parameter s_params[] =
 {
+#ifdef REG_TEST
     { "footprint", Parameter::PT_INT, "0:max32", "0",
         "use zero for production, non-zero for testing at given size (for TCP and user)" },
+#endif
 
     { "ip_frags_only", Parameter::PT_BOOL, nullptr, "false",
             "don't process non-frag flows" },
@@ -130,12 +132,15 @@ bool StreamModule::set(const char* fqn, Value& v, SnortConfig* c)
 {
     PktType type = PktType::NONE;
 
+#ifdef REG_TEST
     if ( v.is("footprint") )
     {
         config.footprint = v.get_uint32();
         return true;
     }
-    else if ( v.is("ip_frags_only") )
+#endif
+
+    if ( v.is("ip_frags_only") )
     {
         if ( v.get_bool() )
             c->set_run_flags(RUN_FLAG__IP_FRAGS_ONLY);
@@ -176,8 +181,6 @@ bool StreamModule::set(const char* fqn, Value& v, SnortConfig* c)
     return true;
 }
 
-// FIXIT-L the detection of stream.xxx_cache changes below is a temporary workaround
-// remove this check when stream.xxx_cache params become reloadable
 bool StreamModule::end(const char*, int, SnortConfig* sc)
 {
     if ( reload_resource_manager.initialize(config) )
@@ -198,22 +201,23 @@ void StreamModule::reset_stats()
 // Stream handler to adjust allocated resources as needed on a config reload
 bool StreamReloadResourceManager::initialize(const StreamModuleConfig& config_)
 {
-    // FIXIT-L - saving config here to check footprint change is a bit of a hack,
-    if ( Snort::is_reloading() )
+    // saving a copy of the config only works here because there is only
+    // one stream inspector per packet thread...
+    if ( !Snort::is_reloading() )
     {
-        if ( config.footprint != config_.footprint )
-        {
-            // FIXIT-M - reinit FlushBucket...
-            ReloadError("Changing of stream.footprint requires a restart\n");
-            return false;
-        }
-
         config = config_;
-        return true;
+        return false;
     }
 
+#ifdef REG_TEST
+    if ( config.footprint != config_.footprint )
+    {
+        ReloadError("Changing of stream.footprint requires a restart\n");
+        return false;
+    }
+#endif
     config = config_;
-    return false;
+    return true;
 }
 
 bool StreamReloadResourceManager::tinit()
index 36af6c365e55eb5addc7cfd86e77a551c0819a56..8bded598376c840dc5ca410caf0c3ca2fc893ed0 100644 (file)
@@ -75,7 +75,10 @@ extern THREAD_LOCAL BaseStats stream_base_stats;
 struct StreamModuleConfig
 {
     FlowCacheConfig flow_cache_cfg;
+#ifdef REG_TEST
     unsigned footprint = 0;
+#endif
+
 };
 
 class StreamReloadResourceManager : public snort::ReloadResourceTuner
index 3100ecd6a27a6403b1cd5b2be8408ba44571ecb8..a8ab9f627c582ba29927223ad3f5f3db3d289d82 100644 (file)
@@ -51,6 +51,9 @@ void FlushBucket::set(unsigned sz)
     assert(s_flush_bucket);
 }
 
+void FlushBucket::set()
+{ set(0); }
+
 void FlushBucket::clear()
 {
     delete s_flush_bucket;
index 0638708845dff46107634ab52c8f7f4a68a48684..3ad3664b13c64fa16424887efabe33d28b537695 100644 (file)
@@ -33,6 +33,7 @@ public:
 
     static uint16_t get_size();
     static void set(unsigned sz);
+    static void set();
     static void clear();
 
 protected:
index 476817e34e524c9d9c07232268a4c895df1f9dc5..cafac897d82531b5e530f1b699cfdcf663192fbb 100644 (file)
@@ -24,7 +24,7 @@
 #include "detection/detection_engine.h"
 #include "framework/ips_option.h"
 #include "framework/module.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "main/snort_config.h"
 #include "profiler/profiler.h"
 
index 0195b432573548eec84314424f821a41f39e5044..70f684ecd20c7e948b27cc2de085de410cb1e0de 100644 (file)
@@ -24,7 +24,7 @@
 #include "framework/ips_option.h"
 #include "framework/module.h"
 #include "framework/range.h"
-#include "hash/hashfcn.h"
+#include "hash/hash_key_operations.h"
 #include "profiler/profiler_defs.h"
 
 #include "tcp_session.h"
index 0504452008878f9535fa6af6a018bb32aef6a758..c06eff91e5a60659d46bf94be6ed86af29ffe492 100644 (file)
@@ -7,11 +7,11 @@ set( UTIL_INCLUDES
     event_gen.h
     infractions.h
     kmap.h
+    memcap_allocator.h
     primed_allocator.h
     safec.h
     segment_mem.h
     sflsq.h
-    sfmemcap.h
     stats.h
     util.h
     util_ber.h
@@ -31,7 +31,6 @@ add_library ( utils OBJECT
     kmap.cc
     segment_mem.cc
     sflsq.cc
-    sfmemcap.cc
     snort_bounds.h
     stats.cc
     util.cc
diff --git a/src/utils/memcap_allocator.h b/src/utils/memcap_allocator.h
new file mode 100644 (file)
index 0000000..4018f86
--- /dev/null
@@ -0,0 +1,107 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// memcap_allocator.h author davis mcpherson davmcphe@cisco.com
+
+// MemCapAllocator manages allocation and freeing of fixed size blocks of memory with
+// an option of limiting total size of allocations to a specified capacity
+
+#ifndef MEMCAP_ALLOCATOR_H
+#define MEMCAP_ALLOCATOR_H
+
+#include "framework/counts.h"
+#include "utils/util.h"
+
+class MemCapAllocator
+{
+public:
+    MemCapAllocator(unsigned long capacity, unsigned long allocation_size)
+        : mem_capacity(capacity), allocation_size(allocation_size)
+    { }
+
+    void* allocate()
+    {
+        void* data = nullptr;
+        if ( is_space_available() )
+        {
+            data = snort_calloc(allocation_size);
+            mem_allocated += allocation_size;
+            ++allocation_requests;
+        }
+        else
+            ++no_memory_available;
+
+        return data;
+    }
+
+    void free(void* mem)
+    {
+        snort_free(mem);
+        mem_allocated -= allocation_size;
+        ++free_requests;
+    }
+
+    bool is_space_available() const
+    {
+        if ( !mem_capacity )
+            return true;
+        else
+            return mem_allocated + allocation_size <= mem_capacity;
+    }
+
+    bool is_over_capacity() const
+    {
+        if ( !mem_capacity )
+            return false;
+        else
+            return mem_allocated > mem_capacity;
+    }
+
+    void set_mem_capacity(unsigned long capacity)
+    { mem_capacity = capacity; }
+
+    unsigned long get_mem_capacity() const
+    { return mem_capacity; }
+
+    unsigned long get_allocation_size() const
+    { return allocation_size; }
+
+    unsigned long get_mem_allocated() const
+    { return mem_allocated; }
+
+    PegCount get_allocation_requests() const
+    { return allocation_requests; }
+
+    PegCount get_free_requests() const
+    { return free_requests; }
+
+    PegCount get_no_memory_available() const
+    { return no_memory_available; }
+
+private:
+    unsigned long mem_capacity;
+    unsigned long allocation_size;
+    unsigned long mem_allocated = 0;
+
+    PegCount allocation_requests = 0;
+    PegCount free_requests = 0;
+    PegCount no_memory_available = 0;
+};
+
+#endif
+
diff --git a/src/utils/sfmemcap.cc b/src/utils/sfmemcap.cc
deleted file mode 100644 (file)
index 31ef821..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2003-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-
-/*
-  sfmemcap.c
-
-  These functions wrap the alloc & free functions. They enforce a memory cap using
-  the MEMCAP structure.  The MEMCAP structure tracks memory usage.  Each allocation
-  has 4 bytes added to it so we can store the allocation size.  This allows us to
-  free a block and accurately track how much memory was recovered.
-
-  Marc Norton
-*/
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "sfmemcap.h"
-
-#include "util.h"
-#include "util_cstring.h"
-
-/*
-*   Set max # bytes & init other variables.
-*/
-void sfmemcap_init(MEMCAP* mc, unsigned long nbytes)
-{
-    mc->memcap = nbytes;
-    mc->memused= 0;
-    mc->nblocks= 0;
-}
-
-/*
-*  Allocate some memory
-*/
-void* sfmemcap_alloc(MEMCAP* mc, unsigned long nbytes)
-{
-    long* data;
-
-    //printf("sfmemcap_alloc: %d bytes requested, memcap=%d,
-    // used=%d\n",nbytes,mc->memcap,mc->memused);
-
-    nbytes += sizeof(long);
-
-    /* Check if we are limiting memory use */
-    if ( mc->memcap > 0 )
-    {
-        /* Check if we've maxed out our memory - if we are tracking memory */
-        if ( (mc->memused + nbytes) > mc->memcap )
-        {
-            return nullptr;
-        }
-    }
-
-    //data = (long*)snort_alloc( nbytes );
-    data = (long*)snort_calloc(nbytes);
-    *data++ = (long)nbytes;
-
-    mc->memused += nbytes;
-    mc->nblocks++;
-
-    return data;
-}
-
-/*
-*   Free some memory
-*/
-void sfmemcap_free(MEMCAP* mc, void* p)
-{
-    long* q;
-
-    q = (long*)p;
-    q--;
-    mc->memused -= (unsigned)(*q);
-    mc->nblocks--;
-
-    snort_free(q);
-}
-
-/*
-*   For debugging.
-*/
-void sfmemcap_showmem(MEMCAP* mc)
-{
-    fprintf(stderr, "memcap: memcap = %lu bytes,",mc->memcap);
-    fprintf(stderr, " memused= %lu bytes,",mc->memused);
-    fprintf(stderr, " nblocks= %d blocks\n",mc->nblocks);
-}
-
diff --git a/src/utils/sfmemcap.h b/src/utils/sfmemcap.h
deleted file mode 100644 (file)
index d2b8043..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2020 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2003-2013 Sourcefire, Inc.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-
-#ifndef SFMEMCAP_H
-#define SFMEMCAP_H
-
-// _alloc and _free wrappers that enforce a memory cap
-
-struct MEMCAP
-{
-    unsigned long memused;
-    unsigned long memcap;
-    int nblocks;
-};
-
-// FIXIT-L could be refactored as a class but should be deleted
-void sfmemcap_init(MEMCAP* mc, unsigned long nbytes);
-void* sfmemcap_alloc(MEMCAP* mc, unsigned long nbytes);
-void sfmemcap_showmem(MEMCAP* mc);
-void sfmemcap_free(MEMCAP* mc, void* memory);
-
-#endif
-
index a9bf39e56c002eed45cbe940d82b6993fdc74017..181baf831159bd0d319f7a44ded61369536e7520 100644 (file)
@@ -3,4 +3,6 @@ add_cpputest( boyer_moore_test
         ../boyer_moore.cc
 )
 
+add_cpputest( memcap_allocator_test )
+
 add_catch_test( bitop_test )
diff --git a/src/utils/test/memcap_allocator_test.cc b/src/utils/test/memcap_allocator_test.cc
new file mode 100644 (file)
index 0000000..3de048e
--- /dev/null
@@ -0,0 +1,221 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2020-2020 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+
+// memcap_allocator_test.cc author davis mcpherson <davmcphe@cisco.com>
+// unit tests for MemCapAllocator class
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "../memcap_allocator.h"
+
+#include <CppUTest/CommandLineTestRunner.h>
+#include <CppUTest/TestHarness.h>
+
+const unsigned long ALLOCATION_SIZE = 250;
+const unsigned long NO_MEM_CAP_LIMIT = 0;
+const unsigned NO_MEMCAP_LIMIT_ALLOCATIONS = 10000;
+
+const unsigned long MEM_CAP_5000 = 5000;
+const unsigned MAX_ALLOCATIONS_5000 = MEM_CAP_5000 / ALLOCATION_SIZE;
+
+const unsigned long MEM_CAP_10000 = 10000;
+const unsigned MAX_ALLOCATIONS_10000 = MEM_CAP_10000 / ALLOCATION_SIZE;
+
+const unsigned long MEM_CAP_20000 = 20000;
+const unsigned MAX_ALLOCATIONS_20000 = MEM_CAP_20000 / ALLOCATION_SIZE;
+
+TEST_GROUP(memcap_allocator)
+{ };
+
+TEST(memcap_allocator, no_memcap_limit_allocator_test)
+{
+    MemCapAllocator* mca = new MemCapAllocator(NO_MEM_CAP_LIMIT, ALLOCATION_SIZE);
+    CHECK(mca);
+    CHECK(mca->get_allocation_size() == ALLOCATION_SIZE);
+    CHECK(mca->get_mem_capacity() == NO_MEM_CAP_LIMIT);
+    CHECK(mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+    CHECK(mca->get_mem_allocated() == 0);
+    CHECK(mca->get_allocation_requests() == 0);
+    CHECK(mca->get_free_requests() == 0);
+    CHECK(mca->get_no_memory_available() == 0);
+    delete mca;
+}
+
+TEST(memcap_allocator, no_memcap_limit_allocations_test)
+{
+    MemCapAllocator* mca = new MemCapAllocator(NO_MEM_CAP_LIMIT, ALLOCATION_SIZE);
+    CHECK(mca);
+
+    unsigned bytes_allocated;
+    uint8_t** mem_blocks = (uint8_t**)snort_alloc(sizeof(uint8_t*) * NO_MEMCAP_LIMIT_ALLOCATIONS);
+    for ( unsigned i = 0; i < NO_MEMCAP_LIMIT_ALLOCATIONS; i++)
+    {
+        mem_blocks[i] = (uint8_t*)mca->allocate();
+        bytes_allocated = (i + 1) * ALLOCATION_SIZE;
+        CHECK(mem_blocks[i]);
+        CHECK(mca->get_mem_allocated() == bytes_allocated);
+        CHECK(mca->is_space_available());
+        CHECK(!mca->is_over_capacity());
+    }
+
+    CHECK(mca->get_allocation_requests() == NO_MEMCAP_LIMIT_ALLOCATIONS);
+    CHECK(mca->get_free_requests() == 0);
+    CHECK(mca->get_no_memory_available() == 0);
+
+    for ( unsigned i = 0; i < NO_MEMCAP_LIMIT_ALLOCATIONS; i++)
+    {
+        mca->free(mem_blocks[i]);
+        bytes_allocated = (NO_MEMCAP_LIMIT_ALLOCATIONS - (i + 1)) * ALLOCATION_SIZE;
+        CHECK(mca->get_mem_allocated() == bytes_allocated);
+    }
+
+    CHECK(mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+    CHECK(mca->get_mem_allocated() == 0);
+    CHECK(mca->get_free_requests() == NO_MEMCAP_LIMIT_ALLOCATIONS);
+    CHECK(mca->get_no_memory_available() == 0);
+
+    snort_free(mem_blocks);
+    delete mca;
+}
+
+TEST(memcap_allocator, create_memcap_allocator_test)
+{
+    MemCapAllocator* mca = new MemCapAllocator(MEM_CAP_10000, ALLOCATION_SIZE);
+    CHECK(mca);
+    CHECK(mca->get_allocation_size() == ALLOCATION_SIZE);
+    CHECK(mca->get_mem_capacity() == MEM_CAP_10000);
+    mca->set_mem_capacity(MEM_CAP_20000);
+    CHECK(mca->get_mem_capacity() == MEM_CAP_20000);
+    CHECK(mca->get_mem_allocated() == 0);
+    CHECK(mca->get_allocation_requests() == 0);
+    CHECK(mca->get_free_requests() == 0);
+    CHECK(mca->get_no_memory_available() == 0);
+    delete mca;
+}
+
+TEST(memcap_allocator, allocate_and_free_memory_test)
+{
+    MemCapAllocator* mca = new MemCapAllocator(MEM_CAP_10000, ALLOCATION_SIZE);
+    CHECK(mca);
+    CHECK(mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+
+    uint8_t* mem = (uint8_t*)mca->allocate();
+    CHECK(mem);
+    CHECK(mca->get_mem_allocated() == ALLOCATION_SIZE);
+    CHECK(mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+    CHECK(mca->get_allocation_requests() == 1);
+    CHECK(mca->get_free_requests() == 0);
+    CHECK(mca->get_no_memory_available() == 0);
+
+    mca->free(mem);
+    CHECK(mca->get_mem_allocated() == 0);
+    CHECK(mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+    CHECK(mca->get_allocation_requests() == 1);
+    CHECK(mca->get_free_requests() == 1);
+    CHECK(mca->get_no_memory_available() == 0);
+
+    delete mca;
+}
+
+TEST(memcap_allocator, max_allocations_test)
+{
+    MemCapAllocator* mca = new MemCapAllocator(MEM_CAP_10000, ALLOCATION_SIZE);
+    CHECK(mca);
+
+    unsigned bytes_allocated;
+    uint8_t* mem_blocks[MAX_ALLOCATIONS_10000];
+    for ( unsigned i = 0; i < MAX_ALLOCATIONS_10000; i++)
+    {
+        mem_blocks[i] = (uint8_t*)mca->allocate();
+        bytes_allocated = (i + 1) * ALLOCATION_SIZE;
+        CHECK(mem_blocks[i]);
+        CHECK(mca->get_mem_allocated() == bytes_allocated);
+        if ( i < MAX_ALLOCATIONS_10000 - 1 )
+        {
+            CHECK(mca->is_space_available());
+        }
+        else
+        {
+            CHECK(!mca->is_space_available());
+        }
+        CHECK(!mca->is_over_capacity());
+    }
+    CHECK(mca->get_allocation_requests() == MAX_ALLOCATIONS_10000);
+    CHECK(mca->get_free_requests() == 0);
+    CHECK(mca->get_no_memory_available() == 0);
+
+    uint8_t* mem = (uint8_t*)mca->allocate();
+    CHECK(!mem);
+    CHECK(mca->get_no_memory_available() == 1);
+    mem = (uint8_t*)mca->allocate();
+    CHECK(!mem);
+    mem = (uint8_t*)mca->allocate();
+    CHECK(!mem);
+    CHECK(mca->get_no_memory_available() == 3);
+    mca->free(mem_blocks[0]);
+    mem_blocks[0] = (uint8_t*)mca->allocate();
+    CHECK(mem_blocks[0]);
+    CHECK(mca->get_free_requests() == 1);
+    CHECK(mca->get_no_memory_available() == 3);
+
+    mca->set_mem_capacity(MEM_CAP_20000);
+    mem = (uint8_t*)mca->allocate();
+    CHECK(mem);
+    mca->set_mem_capacity(MEM_CAP_5000);
+    CHECK(mca->is_over_capacity());
+    mca->free(mem);
+    CHECK(mca->get_free_requests() == 2);
+
+    for ( unsigned i = 0; i < MAX_ALLOCATIONS_5000; i++)
+    {
+        CHECK(!mca->is_space_available());
+        mca->free(mem_blocks[i]);
+        bytes_allocated = (MAX_ALLOCATIONS_10000 - (i + 1)) * ALLOCATION_SIZE;
+        CHECK(mca->get_mem_allocated() == bytes_allocated);
+    }
+
+    CHECK(!mca->is_space_available());
+    CHECK(!mca->is_over_capacity());
+
+    for ( unsigned i = MAX_ALLOCATIONS_5000; i < MAX_ALLOCATIONS_10000; i++)
+    {
+        mca->free(mem_blocks[i]);
+        bytes_allocated = (MAX_ALLOCATIONS_10000 - (i + 1)) * ALLOCATION_SIZE;
+        CHECK(mca->get_mem_allocated() == bytes_allocated);
+        CHECK(mca->is_space_available());
+        CHECK(!mca->is_over_capacity());
+    }
+
+    CHECK(mca->get_mem_allocated() == 0);
+    CHECK(mca->get_free_requests() == MAX_ALLOCATIONS_10000 + 2);
+    CHECK(mca->get_no_memory_available() == 3);
+
+    delete mca;
+}
+
+int main(int argc, char** argv)
+{
+    return CommandLineTestRunner::RunAllTests(argc, argv);
+}