From: Russ Combs (rucombs) Date: Tue, 7 Jun 2016 10:44:57 +0000 (-0400) Subject: Merge pull request #495 in SNORT/snort3 from ha-sc to master X-Git-Tag: 3.0.0-233~378 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=79e8d40f52cec48265ecdb887924fa24c27e2ca3;p=thirdparty%2Fsnort3.git Merge pull request #495 in SNORT/snort3 from ha-sc to master Squashed commit of the following: commit 430c1bd63459e8d2815c0d532af12278d865a07a Author: Ed Borgoyn Date: Mon Jun 6 11:34:27 2016 -0400 Added stub for snort_strdup() commit b0d605d273a4444c22a681aa675a31ef39bc09c4 Merge: 43a60e0 6641e05 Author: Ed Borgoyn Date: Mon Jun 6 11:16:13 2016 -0400 Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc commit 6641e058727b4dad60b7e7fb476868df3dfb4f3a Author: Ed Borgoyn Date: Tue May 31 15:12:25 2016 -0400 Fix problem with udp_ha. commit d58771e037cc54905f5244534d3c0f0d1c3fddb9 Merge: 518749e dc34515 Author: Ed Borgoyn Date: Thu May 26 07:47:39 2016 -0400 Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc commit 518749e07afe7a3532c223c70faa5001f024cc24 Author: Ed Borgoyn Date: Wed May 25 16:21:55 2016 -0400 Additional HA UT's and additional stream HA capabiity. commit dc3451510b5d261c1188a7d57f98b42c18ddd20b Merge: 022b844 5e0a5bb Author: Ed Borgoyn Date: Wed May 25 16:23:59 2016 -0400 Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc Conflicts: src/flow/ha.cc commit 022b8440807ae03c857307e1ce252253a7e4d45b Author: Ed Borgoyn Date: Wed May 25 16:21:55 2016 -0400 Additional HA UT's and additional stream HA capabiity. commit 5e0a5bb14097eb2a3d1ab4e53c7335585afb1699 Author: Ed Borgoyn Date: Thu May 19 10:36:05 2016 -0400 Fix a memory leak in the Flow object regarding the ha_state. commit 02bc6738393e253473f57c6b1367e0fd982ac033 Author: Ed Borgoyn Date: Wed May 18 09:15:29 2016 -0400 Fix mem leak issue in UT. commit d44d4c3631b90a7a136810ac137033d8fe72115e Merge: 9a643a8 b2f8cf7 Author: Ed Borgoyn Date: Wed May 18 07:57:29 2016 -0400 Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 commit b2f8cf7996253e13761d0ec773400a41e14c4b47 Author: Ed Borgoyn Date: Tue May 17 15:02:59 2016 -0400 A few small code review fixes. commit b903d32fe80c4a4f19e80145a420696716cdd535 Author: Ed Borgoyn Date: Fri May 6 10:07:21 2016 -0400 Fix a compile warning. commit bfbd5abccc7a79b3283430a3307ae3402517953d Author: Ed Borgoyn Date: Fri May 6 09:28:29 2016 -0400 Forgot to add the file_connector_module_test to cmake commit a99fb124eeae1e6d52f40a6217cbe61f4ada4a00 Merge: 08612c6 fe16e75 Author: Ed Borgoyn Date: Thu May 5 14:10:32 2016 -0400 Merge branch 'ha-sc' of https://bitbucket-eng-rtp1.cisco.com/bitbucket/scm/snort/snort3 into ha-sc commit 08612c66de9c1750015fcbd1033661931bcda05e Author: Ed Borgoyn Date: Thu May 5 14:08:35 2016 -0400 UT's for file_connector. commit 2c5d4c13e44a644572e012e593e72ebe3d2b2b59 Author: Ed Borgoyn Date: Wed May 4 10:07:52 2016 -0400 Fixed test stubs to eliminate memory leaks. commit cc50492ed3d0f1ef5ded6ffcf3bedc238f7e9e4b Author: Ed Borgoyn Date: Tue May 3 15:06:02 2016 -0400 Makefile.am cosmetic changes. commit 03ff7b57fde7dd0ac747ed2f04707aefed0e6da9 Author: Ed Borgoyn Date: Tue May 3 13:00:14 2016 -0400 Remove extraneous stuff. commit 6b73c2c7ec76339f974875a6aa0f41825f70ea5d Author: Ed Borgoyn Date: Tue May 3 10:53:29 2016 -0400 Additional UT's for side_channel. commit fe16e7515225e59e75c6a975262d99260a1235b1 Author: Ed Borgoyn Date: Wed May 4 10:07:52 2016 -0400 Fixed test stubs to eliminate memory leaks. commit 67dec135d68701f4e12e4eeb94a6b8d86ac85afb Author: Ed Borgoyn Date: Tue May 3 15:06:02 2016 -0400 Makefile.am cosmetic changes. commit b83d121adaed4f6118b14319f6ce2d0dfc46d4f6 Author: Ed Borgoyn Date: Tue May 3 13:00:14 2016 -0400 Remove extraneous stuff. commit 0f903af76892e136b3a86ff538f8bbd5858ba0a6 Author: Ed Borgoyn Date: Tue May 3 10:53:29 2016 -0400 Additional UT's for side_channel. --- diff --git a/src/flow/ha.cc b/src/flow/ha.cc index 635517870..da3730d00 100644 --- a/src/flow/ha.cc +++ b/src/flow/ha.cc @@ -26,6 +26,7 @@ #include "flow.h" #include "flow_key.h" #include "ha_module.h" +#include "log/messages.h" #include "main/snort_debug.h" #include "packet_io/sfdaq.h" #include "profiler/profiler.h" @@ -48,7 +49,7 @@ enum KEY_TYPE_IP4 = 2 }; -typedef std::unordered_map ClientMap; +typedef std::array ClientMap; THREAD_LOCAL SimpleStats ha_stats; THREAD_LOCAL ProfileStats ha_perf_stats; @@ -57,10 +58,11 @@ static THREAD_LOCAL HighAvailability* ha; PortBitSet* HighAvailabilityManager::ports = nullptr; bool HighAvailabilityManager::use_daq_channel = false; struct timeval FlowHAState::min_session_lifetime; -uint8_t FlowHAClient::s_handle_counter = 0; +uint8_t s_handle_counter = 1; // stream client (index == 0) always exists -static THREAD_LOCAL ClientMap* client_map; -static THREAD_LOCAL FlowHAClient* s_session_client; +// The [0] entry contains the stream client (always present) +// Entries [1] to [MAX_CLIENTS-1] contain the optional clients +static THREAD_LOCAL ClientMap* s_client_map; static inline bool is_ip6_key(const FlowKey* key) { @@ -164,22 +166,52 @@ void FlowHAState::reset() pending = NONE_PENDING; } -FlowHAClient::FlowHAClient(bool session_client) +FlowHAClient::FlowHAClient(uint8_t length, bool session_client) { DebugMessage(DEBUG_HA,"FlowHAClient::FlowHAClient()\n"); + if ( !s_client_map ) + return; + + header.length = length; + if ( session_client ) { handle = SESSION_HA_CLIENT; - s_session_client = this; + header.client = SESSION_HA_CLIENT_INDEX; + (*s_client_map)[0] = this; } else { - assert(s_handle_counter != MAX_CLIENTS); - handle = (1 << s_handle_counter); + if ( s_handle_counter >= MAX_CLIENTS ) + { + ErrorMessage("Attempting to register too many FlowHAClients\n"); + return; + } + + header.client = s_handle_counter; + handle = (1 << (s_handle_counter-1)); + (*s_client_map)[s_handle_counter] = this; s_handle_counter += 1; } } +bool FlowHAClient::fit(HAMessage* msg, uint8_t size) +{ + return ( (int)(msg->cursor - msg->content()) < (int)(msg->content_length() - size) ); +} + +bool FlowHAClient::place(HAMessage* msg, uint8_t* data, uint8_t length) +{ + if ( fit(msg, length) ) + { + memcpy(msg->cursor,data,(size_t)length); + msg->cursor += length; + return true; + } + else + return false; +} + // Write the key type, key length, and key into the message. // Does not use the message cursor coming in. // Leave the message cursor just after the key. Return @@ -195,7 +227,7 @@ static uint8_t write_flow_key(Flow* flow, HAMessage* msg) { hdr->key_type = KEY_TYPE_IP6; memcpy(msg->cursor, key, KEY_SIZE_IP6); - msg->cursor = (uint8_t*)hdr + KEY_SIZE_IP6; + msg->cursor += KEY_SIZE_IP6; return KEY_SIZE_IP6; } else @@ -262,15 +294,17 @@ static uint16_t calculate_msg_header_length(Flow* flow) // set of active clients. The Session client is always present. static uint16_t calculate_update_msg_content_length(Flow* flow) { - uint16_t length = s_session_client->get_message_size(); + assert(s_client_map); + assert((*s_client_map)[0]); + uint16_t length = ((*s_client_map)[0]->get_message_size() + sizeof(HAClientHeader)); DebugFormat(DEBUG_HA,"HighAvailability::calculate_update_msg_content_length(): length: %d\n", length); - // Iterating through the hash map is OK to determine length. - for (auto& iter : * client_map ) - if ( flow->ha_state->check_pending(iter.first) ) + for (int i=1; iha_state->check_pending(1<get_message_size(); + assert((*s_client_map)[i]); + length += ((*s_client_map)[i]->get_message_size() + sizeof(HAClientHeader)); DebugFormat(DEBUG_HA, "HighAvailability::calculate_update_msg_content_length(): length: %d\n", length); } @@ -289,19 +323,22 @@ static void write_msg_header(Flow* flow, HAEvent event, uint16_t content_length, write_flow_key(flow, msg); // set cursor to just beyond key } -static void write_update_msg_content(Flow* flow, HAMessage* msg) +static void write_update_msg_client( FlowHAClient* client, Flow* flow, HAMessage* msg) { - // Always have the session portion - s_session_client->produce(flow,msg); + assert(client); + assert(msg); - // Since I'm not sure that the hash map is deterministic, I'll - // step through the clients in order - for ( int i=0; iha_state->check_pending(handle) ) - client_map->find(handle)->second->produce(flow,msg); - } + client->place(msg,(uint8_t*)&(client->header),(uint8_t)sizeof(client->header)); + client->produce(flow, msg); +} + +static void write_update_msg_content(Flow* flow, HAMessage* msg) +{ + assert(s_client_map); + + for ( int i=0; iha_state->check_pending(1<consume(flow,msg) ) - return; + // pointer to the last byte in the message + uint8_t* content_end = msg->content() + msg->content_length() - 1; + + while( msg->cursor <= content_end ) + { + // do we have sufficient message left to be able to have an HAClientHeader? + if ( (int)(content_end - msg->cursor) < (int)sizeof( HAClientHeader ) ) + { + ErrorMessage("Consuming HA Update message - no HAClientHeader\n"); + break; + } + + HAClientHeader* header = (HAClientHeader*)msg->cursor; + msg->cursor += sizeof( HAClientHeader ); // step to the client content + + if ( (header->client >= s_handle_counter) || + ((*s_client_map)[header->client] == nullptr) ) + { + ErrorMessage("Consuming HA Update message - invalid client index\n"); + break; + } + + if ( (content_end - msg->cursor) < header->length ) + { + ErrorMessage("Consuming HA Update memssage - message too short\n"); + break; + } + + if ( !(*s_client_map)[header->client]->consume(flow,msg) ) + { + ErrorMessage("Consuming HA Update message - error from client consume()\n"); + break; + } + } } static void consume_receive_message(HAMessage* msg) @@ -377,7 +445,9 @@ HighAvailability::HighAvailability(PortBitSet* ports, bool) break; } - client_map = new ClientMap; + s_client_map = new ClientMap; + for ( int i=0; iunregister_receive_handler(); } - delete client_map; + delete s_client_map; } void HighAvailability::receive_handler(SCMessage* sc_msg) diff --git a/src/flow/ha.h b/src/flow/ha.h index 1eba39883..d99a8c905 100644 --- a/src/flow/ha.h +++ b/src/flow/ha.h @@ -34,8 +34,12 @@ class Flow; // NOTE: The type, masks, and count values must be in sync, typedef uint16_t FlowHAClientHandle; const FlowHAClientHandle SESSION_HA_CLIENT = 0x0000; +const uint8_t SESSION_HA_CLIENT_INDEX = 0; const FlowHAClientHandle ALL_CLIENTS = 0xffff; -const uint8_t MAX_CLIENTS = 16; +// One client for each mask bit plus one 'automatic' session client +// client handle = (1<<(client_index-1) +// session client has handle of 0 and index of 0 +const uint8_t MAX_CLIENTS = 17; enum HAEvent { @@ -125,12 +129,15 @@ public: virtual ~FlowHAClient() { } virtual bool consume(Flow*, HAMessage*) { return false; } virtual bool produce(Flow*, HAMessage*) { return false; } - virtual size_t get_message_size() { return 0; } + uint8_t get_message_size() { return header.length; } + bool fit(HAMessage*, uint8_t); + bool place(HAMessage*, uint8_t*, uint8_t); FlowHAClientHandle handle; // Actual handle for the instance - static uint8_t s_handle_counter; // next handle to be assigned + HAClientHeader header; protected: - FlowHAClient(bool); // Arg == true for session client + FlowHAClient(uint8_t, bool); + }; // HighAvailability is instantiated for each packet-thread. diff --git a/src/flow/test/CMakeLists.txt b/src/flow/test/CMakeLists.txt index f0765dba2..1e23da9a7 100644 --- a/src/flow/test/CMakeLists.txt +++ b/src/flow/test/CMakeLists.txt @@ -1,2 +1,3 @@ -add_cpputest(ha_test flow) +add_cpputest(ha_test ha) +add_cpputest(ha_module_ha ha_module) diff --git a/src/flow/test/Makefile.am b/src/flow/test/Makefile.am index 251347a5a..3a529e276 100644 --- a/src/flow/test/Makefile.am +++ b/src/flow/test/Makefile.am @@ -2,11 +2,22 @@ AM_DEFAULT_SOURCE_EXT = .cc check_PROGRAMS = \ -ha_test +ha_test \ +ha_module_test TESTS = $(check_PROGRAMS) ha_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@ +ha_module_test_CPPFLAGS = @AM_CPPFLAGS@ @CPPUTEST_CPPFLAGS@ -ha_test_LDADD = ../libflow.a @CPPUTEST_LDFLAGS@ +ha_test_LDADD = \ +../ha.o \ +@CPPUTEST_LDFLAGS@ + +ha_module_test_LDADD = \ +../ha_module.o \ +../../framework/libframework.a \ +../../sfip/libsfip.a \ +../../catch/libcatch_tests.a \ +@CPPUTEST_LDFLAGS@ diff --git a/src/flow/test/ha_module_test.cc b/src/flow/test/ha_module_test.cc new file mode 100644 index 000000000..3e01caf38 --- /dev/null +++ b/src/flow/test/ha_module_test.cc @@ -0,0 +1,164 @@ +//-------------------------------------------------------------------------- +// Copyright (C) 2015-2016 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. +//-------------------------------------------------------------------------- + +// ha_module_test.cc author Ed Borgoyn +// unit test main + +#include +#include + +#include "flow/ha.h" +#include "flow/ha_module.h" + +#include "log/messages.h" +#include "main/snort_debug.h" +#include "profiler/profiler.h" + +void LogMessage(const char*,...) { } + +THREAD_LOCAL SimpleStats ha_stats; +THREAD_LOCAL ProfileStats ha_perf_stats; + +void show_stats(PegCount*, const PegInfo*, unsigned, const char*) { } +void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*) { } +void show_stats(PegCount*, const PegInfo*, IndexVec&, const char*, FILE*) { } + +void ParseWarning(WarningGroup, const char*, ...) { } + +char* snort_strdup(const char* str) { return strdup(str); } + +void Debug::print(const char*, int, uint64_t, const char*, ...) { } + +static bool s_port_1_set = false; +static bool s_use_daq = false; +static bool s_instantiate_called = false; + +static char* make_bit_string(int bit) +{ + static char bit_string[65537]; + for ( int i=0; i<65536; i++) + bit_string[i] = (bit == i) ? '1' : '0'; + + bit_string[65536] = '\0'; + + return bit_string; +} + +bool HighAvailabilityManager::instantiate(PortBitSet* mod_ports, bool mod_use_daq_channel) +{ + s_instantiate_called = true; + s_port_1_set = mod_ports->test(1); + s_use_daq = mod_use_daq_channel; + + return true; +} + +TEST_GROUP(high_availability_module_test) +{ + void setup() + { + } + + void teardown() + { + } +}; + +TEST(high_availability_module_test, test_ha_valid) +{ + Value ports_val(make_bit_string(1)); + Value enable_val(true); + Parameter ports_param = {"ports", Parameter::PT_BIT_LIST, "65535", nullptr, "ports"}; + Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr }; + + HighAvailabilityModule module; + + ports_val.set(&ports_param); + enable_val.set(&enable_param); + + s_instantiate_called = false; + s_port_1_set = false; + s_use_daq = false; + + module.begin("high_availability", 0, nullptr); + module.set("high_availability.ports", ports_val, nullptr); + module.set("high_availability.enable", enable_val, nullptr); + module.end("high_availability", 0, nullptr); + + CHECK(s_instantiate_called == true); + CHECK(s_port_1_set == true); + CHECK(s_use_daq == false); +} + +TEST(high_availability_module_test, test_ha_disabled) +{ + Value enable_val(false); + Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr }; + + HighAvailabilityModule module; + + enable_val.set(&enable_param); + + s_instantiate_called = false; + s_port_1_set = false; + s_use_daq = false; + + module.begin("high_availability", 0, nullptr); + module.set("high_availability.enable", enable_val, nullptr); + module.end("high_availability", 0, nullptr); + + CHECK(s_instantiate_called == false); + CHECK(s_port_1_set == false); + CHECK(s_use_daq == false); +} + +TEST(high_availability_module_test, test_ha_valid_daq) +{ + Value ports_val(make_bit_string(1)); + Value enable_val(true); + Value daq_val(true); + Parameter ports_param = {"ports", Parameter::PT_BIT_LIST, "65535", nullptr, "ports"}; + Parameter enable_param = {"enable", Parameter::PT_BOOL, nullptr, "false", nullptr }; + Parameter daq_param = {"daq_channel", Parameter::PT_BOOL, nullptr, "false", nullptr }; + + HighAvailabilityModule module; + + ports_val.set(&ports_param); + enable_val.set(&enable_param); + daq_val.set(&daq_param); + + s_instantiate_called = false; + s_port_1_set = false; + s_use_daq = false; + + module.begin("high_availability", 0, nullptr); + module.set("high_availability.ports", ports_val, nullptr); + module.set("high_availability.enable", enable_val, nullptr); + module.set("high_availability.daq_channel", daq_val, nullptr); + module.end("high_availability", 0, nullptr); + + CHECK(s_instantiate_called == true); + CHECK(s_port_1_set == true); + CHECK(s_use_daq == true); +} + +int main(int argc, char** argv) +{ + return CommandLineTestRunner::RunAllTests(argc, argv); +} + diff --git a/src/flow/test/ha_test.cc b/src/flow/test/ha_test.cc index 8fe22bd97..7112c611d 100644 --- a/src/flow/test/ha_test.cc +++ b/src/flow/test/ha_test.cc @@ -29,11 +29,47 @@ #include "stream/stream_api.h" #define MSG_SIZE 100 +#define TEST_KEY 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47 + +class StreamHAClient; + +static const uint8_t s_test_key[] = +{ +TEST_KEY +}; + +static const uint8_t s_delete_message[] = +{ + 0x01, + 0x03, + 0x00, + 0x00, + 0x01, +TEST_KEY +}; + + +static struct timeval s_time = { 0, 0 }; +static uint8_t s_message[MSG_SIZE]; +static SideChannel s_side_channel; +static SCMessage s_sc_message; +static SCMessage s_rec_sc_message; +static bool s_get_session_called = false; +static bool s_delete_session_called = false; +static bool s_transmit_message_called = false; +static uint8_t* s_message_content = nullptr; +static uint8_t s_message_length = 0; +static Flow s_flow; +static FlowKey s_flowkey; +static DAQ_PktHdr_t s_pkthdr; +static StreamHAClient* ha_client; +static std::function s_handler = nullptr; +static SCMsgHdr s_sc_header = { 0, 1, 0, 0, }; class StreamHAClient : public FlowHAClient { public: - StreamHAClient() : FlowHAClient(true) { } + StreamHAClient() : FlowHAClient(10, true) { } ~StreamHAClient() { } bool consume(Flow*, HAMessage*) { return true; } bool produce(Flow*, HAMessage* msg) @@ -42,22 +78,25 @@ public: *(msg->cursor)++ = i; return true; } - size_t get_message_size() { return 10; } + uint8_t get_message_size() { return 10; } private: }; -static struct timeval s_time = { 0, 0 }; -static uint8_t message[MSG_SIZE]; -static SideChannel s_side_channel; -static SCMessage s_sc_message; -static Flow s_flow; -static DAQ_PktHdr_t s_pkthdr; - -Flow* Stream::get_session(const FlowKey*) { return &s_flow; } +Flow* Stream::get_session(const FlowKey* flowkey) +{ + s_flowkey = *flowkey; + s_get_session_called = true; + return &s_flow; +} -void Stream::delete_session(const FlowKey*) { } +void Stream::delete_session(const FlowKey* flowkey) +{ + s_flowkey = *flowkey; + s_delete_session_called = true; +} +void ErrorMessage(const char*,...) { } void LogMessage(const char*,...) { } void Debug::print(const char*, int, uint64_t, const char*, ...) { } @@ -80,7 +119,10 @@ Connector::Direction SideChannel::get_direction() void SideChannel::set_default_port(SCPort) { } -void SideChannel::register_receive_handler(std::function) { } +void SideChannel::register_receive_handler(std::function handler) +{ + s_handler = handler; +} void SideChannel::unregister_receive_handler() { } @@ -88,40 +130,50 @@ bool SideChannel::discard_message(SCMessage*) { return true; } bool SideChannel::process(int) -{ return false; } +{ + if ( s_handler && s_message_content && (s_message_length != 0)) + { + s_rec_sc_message.content = s_message_content; + s_rec_sc_message.content_length = s_message_length; + s_rec_sc_message.hdr = &s_sc_header; + s_rec_sc_message.sc = &s_side_channel; + s_handler(&s_rec_sc_message); + return true; + } + else + return false; +} -bool SideChannel::transmit_message(SCMessage*) -{ return true; } +bool SideChannel::transmit_message(SCMessage* msg) +{ + s_transmit_message_called = true; + s_message_content = msg->content; + s_message_length = msg->content_length; + return true; } SCMessage* SideChannel::alloc_transmit_message(uint32_t len) { if ( len > MSG_SIZE ) return nullptr; - s_sc_message.content = message; + s_sc_message.content = s_message; s_sc_message.content_length = len; return &s_sc_message; } TEST_GROUP(high_availability_manager_test) { - StreamHAClient* ha_client; void setup() { - ha_client = new StreamHAClient; + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); } void teardown() { - delete ha_client; + MemoryLeakWarningPlugin::turnOnNewDeleteOverloads(); } }; -TEST(high_availability_manager_test, pre_config_init) -{ - HighAvailabilityManager::pre_config_init(); -} - TEST(high_availability_manager_test, init_term) { HighAvailabilityManager::pre_config_init(); @@ -138,35 +190,9 @@ TEST(high_availability_manager_test, inst_init_term) port_set.set(1); HighAvailabilityManager::instantiate(&port_set, false); HighAvailabilityManager::thread_init(); + ha_client = new StreamHAClient; CHECK(HighAvailabilityManager::active()==true); - HighAvailabilityManager::thread_term(); - CHECK(HighAvailabilityManager::active()==false); -} - -TEST(high_availability_manager_test, inst_init_deletion_term) -{ - HighAvailabilityManager::pre_config_init(); - PortBitSet port_set; - port_set.set(1); - HighAvailabilityManager::instantiate(&port_set, false); - HighAvailabilityManager::thread_init(); - CHECK(HighAvailabilityManager::active()==true); - HighAvailabilityManager::process_receive(); - HighAvailabilityManager::process_deletion(&s_flow); - HighAvailabilityManager::thread_term(); - CHECK(HighAvailabilityManager::active()==false); -} - -TEST(high_availability_manager_test, inst_init_update_term) -{ - HighAvailabilityManager::pre_config_init(); - PortBitSet port_set; - port_set.set(1); - HighAvailabilityManager::instantiate(&port_set, false); - HighAvailabilityManager::thread_init(); - CHECK(HighAvailabilityManager::active()==true); - HighAvailabilityManager::process_update(&s_flow, &s_pkthdr); - HighAvailabilityManager::process_receive(); + delete ha_client; HighAvailabilityManager::thread_term(); CHECK(HighAvailabilityManager::active()==false); } @@ -175,19 +201,47 @@ TEST_GROUP(high_availability_test) { void setup() { + MemoryLeakWarningPlugin::turnOffNewDeleteOverloads(); HighAvailabilityManager::pre_config_init(); PortBitSet port_set; port_set.set(1); HighAvailabilityManager::instantiate(&port_set, false); HighAvailabilityManager::thread_init(); + ha_client = new StreamHAClient; } void teardown() { + delete ha_client; HighAvailabilityManager::thread_term(); + MemoryLeakWarningPlugin::turnOnNewDeleteOverloads(); } }; +TEST(high_availability_test, receive_deletion) +{ + s_delete_session_called = false; + s_message_content = (uint8_t*)s_delete_message; + s_message_length = sizeof(s_delete_message); + HighAvailabilityManager::process_receive(); + CHECK(s_delete_session_called == true); + CHECK(memcmp((const void*)&s_flowkey, (const void*)&s_test_key, sizeof(s_test_key)) == 0); +} + +TEST(high_availability_test, transmit_deletion) +{ + s_transmit_message_called = false; + HighAvailabilityManager::process_deletion(&s_flow); + CHECK(s_transmit_message_called == true); +} + +TEST(high_availability_test, transmit_update_stream_only) +{ + s_transmit_message_called = false; + HighAvailabilityManager::process_update(&s_flow, &s_pkthdr); + CHECK(s_transmit_message_called == true); +} + int main(int argc, char** argv) { return CommandLineTestRunner::RunAllTests(argc, argv); diff --git a/src/main/snort.cc b/src/main/snort.cc index 03ad8806e..030e013d0 100644 --- a/src/main/snort.cc +++ b/src/main/snort.cc @@ -646,9 +646,9 @@ void Snort::thread_init_unprivileged() EventManager::open_outputs(); IpsManager::setup_options(); ActionManager::thread_init(snort_conf); - InspectorManager::thread_init(snort_conf); SideChannelManager::thread_init(); - HighAvailabilityManager::thread_init(); + HighAvailabilityManager::thread_init(); // must be before InspectorManager::thread_init(); + InspectorManager::thread_init(snort_conf); } void Snort::thread_term() diff --git a/src/stream/base/stream_ha.cc b/src/stream/base/stream_ha.cc index b43cf1b56..f0ef75626 100644 --- a/src/stream/base/stream_ha.cc +++ b/src/stream/base/stream_ha.cc @@ -56,16 +56,18 @@ void ProtocolHA::process_deletion(Flow* flow) HighAvailabilityManager::process_deletion(flow); } -THREAD_LOCAL StreamHAClient* StreamHAManager::ha_client; +THREAD_LOCAL StreamHAClient* StreamHAManager::ha_client = nullptr; void StreamHAManager::tinit() { - ha_client = new StreamHAClient(); + if ( HighAvailabilityManager::active() ) + ha_client = new StreamHAClient(); } void StreamHAManager::tterm() { - delete ha_client; + if ( ha_client ) + delete ha_client; } void StreamHAManager::process_deletion(Flow*) diff --git a/src/stream/base/stream_ha.h b/src/stream/base/stream_ha.h index 6bc7ae35f..7b1f78b96 100644 --- a/src/stream/base/stream_ha.h +++ b/src/stream/base/stream_ha.h @@ -29,11 +29,9 @@ class StreamHAClient : public FlowHAClient { public: - StreamHAClient() : FlowHAClient(true) { } + StreamHAClient() : FlowHAClient(sizeof(LwState), true) { } bool consume(Flow*, HAMessage*); bool produce(Flow*, HAMessage*); - size_t get_message_size() - { return sizeof(LwState); } private: }; diff --git a/src/stream/udp/udp_ha.cc b/src/stream/udp/udp_ha.cc index 66227886e..91966f12f 100644 --- a/src/stream/udp/udp_ha.cc +++ b/src/stream/udp/udp_ha.cc @@ -31,15 +31,25 @@ void UdpHA::create_session(Flow*) DebugMessage(DEBUG_HA,"UdpHA::create_session)\n"); } -THREAD_LOCAL UdpHA* UdpHAManager::udp_ha; +THREAD_LOCAL UdpHA* UdpHAManager::udp_ha = nullptr; + +void UdpHAManager::process_deletion(Flow* flow) +{ + if( udp_ha != nullptr ) + udp_ha->process_deletion(flow); +} void UdpHAManager::tinit() { - udp_ha = new UdpHA(); + if ( HighAvailabilityManager::active() ) + udp_ha = new UdpHA(); + else + udp_ha = nullptr; } void UdpHAManager::tterm() { - delete udp_ha; + if ( udp_ha ) + delete udp_ha; } diff --git a/src/stream/udp/udp_ha.h b/src/stream/udp/udp_ha.h index 4f69d29c8..bcfdfb9c0 100644 --- a/src/stream/udp/udp_ha.h +++ b/src/stream/udp/udp_ha.h @@ -40,8 +40,7 @@ private: class UdpHAManager { public: - static void process_deletion(Flow* flow) - { udp_ha->process_deletion(flow); } + static void process_deletion(Flow* flow); static void tinit(); static void tterm(); static THREAD_LOCAL UdpHA* udp_ha;