get_data_bus()._subscribe(key, h);
}
+// for subscribers that need to receive events regardless of active inspection policy
+void DataBus::subscribe_default(const char* key, DataHandler* h)
+{
+ get_default_inspection_policy(SnortConfig::get_conf())->dbus._subscribe(key, h);
+}
+
+void DataBus::unsubscribe(const char* key, DataHandler* h)
+{
+ get_data_bus()._unsubscribe(key, h);
+}
+
+void DataBus::unsubscribe_default(const char* key, DataHandler* h)
+{
+ get_default_inspection_policy(SnortConfig::get_conf())->dbus._unsubscribe(key, h);
+}
+
// notify subscribers of event
void DataBus::publish(const char* key, DataEvent& e, Flow* f)
{
void DataBus::publish(const char* key, Packet* p, Flow* f)
{
PacketEvent e(p);
- if ( !f )
+ if ( p && !f )
f = p->flow;
publish(key, e, f);
}
v.push_back(h);
}
+void DataBus::_unsubscribe(const char* key, DataHandler* h)
+{
+ DataList& v = map[key];
+
+ for ( unsigned i = 0; i < v.size(); i++ )
+ if ( v[i] == h )
+ v.erase(v.begin() + i--);
+
+ if ( v.empty() )
+ map.erase(key);
+}
+
// notify subscribers of event
void DataBus::_publish(const char* key, DataEvent& e, Flow* f)
{
~DataBus();
static void subscribe(const char* key, DataHandler*);
+ static void subscribe_default(const char* key, DataHandler*);
+ static void unsubscribe(const char* key, DataHandler*);
+ static void unsubscribe_default(const char* key, DataHandler*);
static void publish(const char* key, DataEvent&, Flow* = nullptr);
// convenience methods
private:
void _subscribe(const char* key, DataHandler*);
+ void _unsubscribe(const char* key, DataHandler*);
void _publish(const char* key, DataEvent&, Flow*);
private:
// common data events
#define PACKET_EVENT "detection.packet"
#define DAQ_META_EVENT "daq.metapacket"
+#define FLOW_STATE_EVENT "flow.state_change"
+#define THREAD_IDLE_EVENT "thread.idle"
+#define THREAD_ROTATE_EVENT "thread.rotate"
#endif
void set_default_policy()
{ set_default_policy(SnortConfig::get_conf()); }
+bool default_inspection_policy()
+{
+ if ( !get_inspection_policy() )
+ return false;
+
+ if ( get_inspection_policy()->policy_id != 0 )
+ return false;
+
+ return true;
+}
+
bool only_inspection_policy()
{ return get_inspection_policy() && !get_ips_policy() && !get_network_policy(); }
void set_default_policy();
void set_default_policy(snort::SnortConfig*);
+bool default_inspection_policy();
bool only_inspection_policy();
bool only_ips_policy();
bool only_network_policy();
#include "packet_io/trough.h"
#include "parser/cmd_line.h"
#include "parser/parser.h"
-#include "perf_monitor/perf_monitor.h"
#include "profiler/profiler.h"
#include "search_engines/search_engines.h"
#include "service_inspectors/service_inspectors.h"
void Snort::thread_idle()
{
+ // FIXIT-L this whole thing could be pub-sub
+ DataBus::publish(THREAD_IDLE_EVENT, nullptr);
Stream::timeout_flows(time(nullptr));
- perf_monitor_idle_process();
aux_counts.idle++;
HighAvailabilityManager::process_receive();
}
void Snort::thread_rotate()
{
- SetRotatePerfFileFlag();
+ DataBus::publish(THREAD_ROTATE_EVENT, nullptr);
}
/*
break;
case IT_PROBE:
- probe.add(p);
+ {
+ // probes always run
+ // add them to default so they can be found on InspectorManager::probe
+ SnortConfig* sc = SnortConfig::get_conf();
+ sc->policy_map->get_inspection_policy(0)->framework_policy->probe.add(p);
break;
+ }
case IT_MAX:
break;
void InspectorManager::probe(Packet* p)
{
- FrameworkPolicy* fp = snort::get_inspection_policy()->framework_policy;
+ InspectionPolicy* policy = snort::SnortConfig::get_conf()->policy_map->get_inspection_policy(0);
+ FrameworkPolicy* fp = policy->framework_policy;
::execute(p, fp->probe.vec, fp->probe.num);
}
return found;
}
+ if ( mod->get_usage() == Module::GLOBAL &&
+ only_inspection_policy() && !default_inspection_policy() )
+ return true;
+
if ( mod->get_usage() != Module::INSPECT && only_inspection_policy() )
- return true;
+ return true;
if ( mod->get_usage() != Module::DETECT && only_ips_policy() )
- return true;
+ return true;
if ( mod->get_usage() != Module::CONTEXT && only_network_policy() )
- return true;
+ return true;
// now we must traverse the mod params to get the leaf
string s = fqn;
Module* m = h->mod;
const Parameter* p = nullptr;
+ if ( m->get_usage() == Module::GLOBAL &&
+ only_inspection_policy() && !default_inspection_policy() )
+ return true;
+
if ( m->get_usage() != Module::INSPECT && only_inspection_policy() )
return true;
if ( ModHook* h = get_hook(key.c_str()) )
{
+ if ( h->mod->get_usage() == Module::GLOBAL &&
+ only_inspection_policy() && !default_inspection_policy() )
+ return;
+
if ( h->mod->get_usage() != Module::INSPECT && only_inspection_policy() )
return;
static void add_plugin(Plugin& p)
{
+ Module* m = nullptr;
if ( p.api->mod_ctor )
{
current_plugin = p.api->name;
- Module* m = p.api->mod_ctor();
+ m = p.api->mod_ctor();
ModuleManager::add_module(m, p.api);
}
break;
case PT_INSPECTOR:
+ // probes must always be global. they run regardless of selected policy.
+ assert( (m && ((const InspectApi*)p.api)->type == IT_PROBE) ?
+ m->get_usage() == Module::GLOBAL :
+ true );
+
InspectorManager::add_plugin((const InspectApi*)p.api);
break;
set(STATIC_INSPECTOR_OBJS
$<TARGET_OBJECTS:arp_spoof>
$<TARGET_OBJECTS:packet_capture>
+ $<TARGET_OBJECTS:perf_monitor>
)
endif()
$<TARGET_OBJECTS:appid>
$<TARGET_OBJECTS:binder>
$<TARGET_OBJECTS:normalize>
- $<TARGET_OBJECTS:perf_monitor>
$<TARGET_OBJECTS:port_scan>
$<TARGET_OBJECTS:reputation>
${STATIC_INSPECTOR_OBJS}
network_inspectors.cc
network_inspectors.h
)
-
extern const BaseApi* nin_binder;
extern const BaseApi* nin_normalize;
-extern const BaseApi* nin_perf_monitor;
extern const BaseApi* nin_reputation;
extern const BaseApi* nin_appid[];
#ifdef STATIC_INSPECTORS
extern const BaseApi* nin_arp_spoof[];
extern const BaseApi* nin_packet_capture[];
+extern const BaseApi* nin_perf_monitor[];
#endif
static const BaseApi* network_inspectors[] =
{
nin_binder,
nin_normalize,
- nin_perf_monitor,
nin_reputation,
nullptr
};
#ifdef STATIC_INSPECTORS
PluginManager::load_plugins(nin_arp_spoof);
PluginManager::load_plugins(nin_packet_capture);
+ PluginManager::load_plugins(nin_perf_monitor);
#endif
}
void get_config(CaptureConfig&);
Usage get_usage() const override
- { return CONTEXT; }
+ { return GLOBAL; }
private:
CaptureConfig config;
mod_ctor,
mod_dtor
},
- IT_PACKET,
+ IT_PROBE,
(uint16_t)PktType::ANY,
nullptr, // buffers
nullptr, // service
perf_module.cc
perf_module.h
perf_monitor.cc
- perf_monitor.h
perf_tracker.cc
perf_tracker.h
text_formatter.cc
using namespace snort;
using namespace std;
-BaseTracker::BaseTracker(PerfConfig* perf)
- : PerfTracker(perf, perf->output == PERF_FILE, PERF_NAME "_base")
+BaseTracker::BaseTracker(PerfConfig* perf) : PerfTracker(perf, PERF_NAME "_base")
{
- for (unsigned i = 0; i < config->modules.size(); i++)
+ for ( ModuleConfig& mod : config->modules )
{
- Module *m = config->modules.at(i);
- IndexVec peg_map = config->mod_peg_idxs.at(i);
+ formatter->register_section(mod.ptr->get_name());
- formatter->register_section(m->get_name());
-
- for (auto const& peg : peg_map)
- formatter->register_field(m->get_pegs()[peg].name, &(m->get_counts()[peg]));
+ for ( auto const& idx : mod.pegs )
+ formatter->register_field(mod.ptr->get_pegs()[idx].name, &(mod.ptr->get_counts()[idx]));
}
formatter->finalize_fields();
}
{
write();
- for ( auto const& m : config->modules )
- if (!summary)
- m->sum_stats(false);
+ for ( auto const& mod : config->modules )
+ if ( !summary )
+ mod.ptr->sum_stats(false);
}
#ifdef UNIT_TEST
{0, 0, 0}};
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
MockModule mod;
- config.modules.push_back(&mod);
- config.mod_peg_idxs.push_back(IndexVec());
- config.mod_peg_idxs[0].push_back(0);
- config.mod_peg_idxs[0].push_back(2);
- config.mod_peg_idxs[0].push_back(4);
+ ModuleConfig mod_cfg;
+ mod_cfg.ptr = &mod;
+ mod_cfg.pegs = {0, 2, 4};
+ config.modules.push_back(mod_cfg);
MockBaseTracker tracker(&config);
MockFormatter *formatter = (MockFormatter*)tracker.output;
return (uint64_t)t.tv_sec * 1000000 + t.tv_usec;
}
-CPUTracker::CPUTracker(PerfConfig *perf) :
- PerfTracker(perf, perf->output == PERF_FILE, TRACKER_NAME)
+CPUTracker::CPUTracker(PerfConfig *perf) : PerfTracker(perf, TRACKER_NAME)
{
formatter->register_section("thread_" + to_string(get_instance_id()));
formatter->register_field("cpu_user", &user_stat);
{2100000, 3200000, 8500000}};
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
TestCPUTracker tracker(&config);
MockFormatter *formatter = (MockFormatter*)tracker.output;
#include "flow_ip_tracker.h"
+#include "framework/data_bus.h"
#include "log/messages.h"
#include "protocols/packet.h"
SfIp ipB;
};
-THREAD_LOCAL FlowIPTracker* perf_flow_ip;
+class FlowIPDataHandler : public DataHandler
+{
+public:
+ FlowIPDataHandler(FlowIPTracker& t) : tracker(t)
+ { DataBus::subscribe_default(FLOW_STATE_EVENT, this); }
+
+ virtual void handle(DataEvent&, Flow* flow) override
+ {
+ FlowState state = SFS_STATE_MAX;
+
+ if ( flow->pkt_type == PktType::UDP )
+ state = SFS_STATE_UDP_CREATED;
+
+ if ( flow->pkt_type == PktType::TCP )
+ {
+ if ( flow->get_session_flags() & SSNFLAG_COUNTED_ESTABLISH )
+ state = SFS_STATE_TCP_ESTABLISHED;
+
+ if ( flow->get_session_flags() & SSNFLAG_COUNTED_CLOSED )
+ state = SFS_STATE_TCP_CLOSED;
+ }
+
+ if ( state == SFS_STATE_MAX )
+ return;
+
+ tracker.update_state(&flow->client_ip, &flow->server_ip, state);
+ }
+
+private:
+ FlowIPTracker& tracker;
+};
FlowStateValue* FlowIPTracker::find_stats(const SfIp* src_addr, const SfIp* dst_addr,
int* swapped)
{
FlowStateKey key;
- FlowStateValue* value;
+ FlowStateValue* value = nullptr;
if (src_addr->less_than(*dst_addr))
{
return value;
}
-FlowIPTracker::FlowIPTracker(PerfConfig* perf) :
- PerfTracker(perf, perf->output == PERF_FILE, TRACKER_NAME)
+FlowIPTracker::FlowIPTracker(PerfConfig* perf) : PerfTracker(perf, TRACKER_NAME)
{
+ handler = new FlowIPDataHandler(*this);
+
formatter->register_section("flow_ip");
formatter->register_field("ip_a", ip_a);
formatter->register_field("ip_b", ip_b);
formatter->finalize_fields();
ip_map = xhash_new(1021, sizeof(FlowStateKey), sizeof(FlowStateValue),
- perfmon_config->flowip_memcap, 1, nullptr, nullptr, 1);
+ perf->flowip_memcap, 1, nullptr, nullptr, 1);
if (!ip_map)
FatalError("Unable to allocate memory for FlowIP stats\n");
FlowIPTracker::~FlowIPTracker()
{
- if (ip_map)
+ DataBus::unsubscribe_default(FLOW_STATE_EVENT, handler);
+ delete handler;
+
+ if ( ip_map )
xhash_delete(ip_map);
}
#define FLOW_IP_TRACKER_H
#include "perf_tracker.h"
+
#include "hash/xhash.h"
enum FlowState
struct FlowStateValue
{
TrafficStats traffic_stats[SFS_TYPE_MAX];
- uint64_t total_packets;
- uint64_t total_bytes;
- uint32_t state_changes[SFS_STATE_MAX];
+ PegCount total_packets;
+ PegCount total_bytes;
+ PegCount state_changes[SFS_STATE_MAX];
};
+class FlowIPDataHandler;
class FlowIPTracker : public PerfTracker
{
public:
int update_state(const snort::SfIp* src_addr, const snort::SfIp* dst_addr, FlowState);
private:
+ FlowIPDataHandler* handler;
FlowStateValue stats;
XHash* ip_map;
char ip_a[41], ip_b[41];
void write_stats();
void display_stats();
};
-
-extern THREAD_LOCAL FlowIPTracker* perf_flow_ip;
#endif
#define MAX_PKT_LEN 9000
-FlowTracker::FlowTracker(PerfConfig* perf) : PerfTracker(perf,
- perf->output == PERF_FILE, TRACKER_NAME)
+FlowTracker::FlowTracker(PerfConfig* perf) : PerfTracker(perf, TRACKER_NAME)
{
pkt_len_cnt.resize( MAX_PKT_LEN + 1 );
tcp.src.resize( config->flow_max_port_to_track + 1, 0 );
uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
config.flow_max_port_to_track = 1024;
MockFlowTracker tracker(&config);
uint8_t* type_ptr = (uint8_t*) &icmp.type;
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
config.flow_max_port_to_track = 1024;
MockFlowTracker tracker(&config);
uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
config.flow_max_port_to_track = 1024;
MockFlowTracker tracker(&config);
uint32_t* len_ptr = &const_cast<DAQ_PktHdr_t*>(p.pkth)->caplen;
PerfConfig config;
- config.format = PERF_MOCK;
+ config.format = PerfFormat::MOCK;
config.flow_max_port_to_track = 1024;
MockFlowTracker tracker(&config);
#include "perf_module.h"
+#include "log/messages.h"
#include "managers/module_manager.h"
using namespace snort;
}
else if ( v.is("name") )
{
- mod_name = v.get_string();
+ config.modules.back().set_name(v.get_string());
}
else if ( v.is("pegs") )
{
- mod_pegs = v.get_string();
+ config.modules.back().set_peg_names(v);
}
else if ( v.is("summary") )
{
return true;
}
-bool PerfMonModule::begin(const char* fqn, int, SnortConfig*)
+bool PerfMonModule::begin(const char* fqn, int idx, SnortConfig*)
{
- if ( !strcmp(fqn, "perf_monitor.modules") )
- {
- mod_name.clear();
- mod_pegs.clear();
- }
- else
- memset(static_cast<PerfConfigBase*>(&config), 0, sizeof(config));
+ if ( idx != 0 && strcmp(fqn, "perf_monitor.modules") == 0 )
+ config.modules.push_back(ModuleConfig());
return true;
}
-static bool add_module(PerfConfig& config, Module *mod, std::string& pegs)
+bool PerfMonModule::end(const char* fqn, int idx, SnortConfig*)
+{
+ if ( idx != 0 && strcmp(fqn, "perf_monitor.modules") == 0 )
+ return config.modules.back().confirm_parse();
+
+ return true;
+}
+
+PerfConfig& PerfMonModule::get_config()
+{ return config; }
+
+const PegInfo* PerfMonModule::get_pegs() const
+{ return simple_pegs; }
+
+PegCount* PerfMonModule::get_counts() const
+{ return (PegCount*)&pmstats; }
+
+void ModuleConfig::set_name(std::string name)
+{ this->name = name; }
+
+void ModuleConfig::set_peg_names(Value& peg_names)
{
- const PegInfo* peg_info;
std::string tok;
- Value v(pegs.c_str());
- unsigned t_count = 0;
+ peg_names.set_first_token();
- if ( !mod )
+ while ( peg_names.get_next_token(tok) )
+ this->peg_names[tok] = false;
+}
+
+bool ModuleConfig::confirm_parse()
+{
+ // asking for pegs without specifying the module name doesn't make sense
+ if ( name.empty() && !peg_names.empty() )
return false;
- config.modules.push_back(mod);
- config.mod_peg_idxs.push_back(std::vector<unsigned>());
+ return true;
+}
+bool ModuleConfig::resolve()
+{
+ ptr = ModuleManager::get_module(name.c_str());
+ if ( ptr == nullptr )
+ {
+ ParseWarning(WARN_CONF, "Perf monitor is unable to find the %s module.\n", name.c_str());
+ return false;
+ }
- peg_info = mod->get_pegs();
+ const PegInfo* peg_info = ptr->get_pegs();
+ if ( !peg_info )
+ return true; // classifications does this. it's valid.
- for ( v.set_first_token(); v.get_next_token(tok); t_count++ )
+ if ( peg_names.empty() )
{
- bool found = false;
+ for ( unsigned i = 0; peg_info[i].name != nullptr; i++ )
+ pegs.push_back(i);
+ }
+ else
+ {
+ for ( unsigned i = 0; peg_info[i].name != nullptr; i++ )
+ {
+ auto peg_ittr = peg_names.find(peg_info[i].name);
- for ( int i = 0; peg_info[i].name; i++ )
+ if ( peg_ittr != peg_names.end() )
+ {
+ peg_ittr->second = true;
+ pegs.push_back(i);
+ }
+ }
+
+ for ( auto &i : peg_names )
{
- if ( !strcmp(tok.c_str(), peg_info[i].name) )
+ if ( !i.second )
{
- config.mod_peg_idxs.back().push_back(i);
- found = true;
- break;
+ ParseWarning(WARN_CONF, "Perf monitor is unable to find %s.%s count", name.c_str(), i.first.c_str());
+ return false;
}
}
- if ( !found )
- return false;
}
- if ( !t_count && peg_info )
- for ( int i = 0; peg_info[i].name; i++ )
- config.mod_peg_idxs.back().push_back(i);
+ name.clear();
+ peg_names.clear();
return true;
}
-bool PerfMonModule::end(const char* fqn, int idx, SnortConfig*)
+bool PerfConfig::resolve()
{
- if ( !idx )
+ if ( modules.empty() )
{
- if ( config.modules.empty() )
+ auto all_modules = ModuleManager::get_all_modules();
+ for ( auto& mod : all_modules )
{
- auto modules = ModuleManager::get_all_modules();
- std::string empty;
-
- for ( auto& mod : modules )
- {
- if ( !add_module(config, mod, empty) )
- return false;
- }
+ ModuleConfig cfg;
+ cfg.set_name(mod->get_name());
+ modules.push_back(cfg);
}
- return true;
}
- if ( !strcmp(fqn, "perf_monitor.modules") && !mod_name.empty() )
- return add_module(config, ModuleManager::get_module(mod_name.c_str()), mod_pegs);
+ for ( auto& mod : modules )
+ if ( !mod.resolve() )
+ return false;
return true;
}
-
-void PerfMonModule::get_config(PerfConfig& cfg)
-{
- cfg = config;
-}
-
-const PegInfo* PerfMonModule::get_pegs() const
-{ return simple_pegs; }
-
-PegCount* PerfMonModule::get_counts() const
-{ return (PegCount*)&pmstats; }
-
#ifndef PERF_MODULE_H
#define PERF_MODULE_H
+#include <unordered_map>
+
#include "framework/module.h"
#define PERF_NAME "perf_monitor"
#define MAX_PERF_FILE_SIZE UINT64_MAX
#define MIN_PERF_FILE_SIZE 4096
-enum PerfFormat
+enum class PerfFormat
{
- PERF_CSV,
- PERF_TEXT,
- PERF_JSON,
- PERF_FBS,
- PERF_MOCK
+ CSV,
+ TEXT,
+ JSON,
+ FBS,
+ MOCK
};
-enum PerfOutput
+enum class PerfOutput
{
- PERF_FILE,
- PERF_CONSOLE
+ TO_FILE,
+ TO_CONSOLE
};
-struct PerfConfigBase
+struct ModuleConfig
{
+ // state optimized for run time using indicies
+ // can't be determined until all modules have loaded (PerfMonitor::configure)
+ snort::Module* ptr;
+ IndexVec pegs;
+
+ void set_name(std::string name);
+ void set_peg_names(snort::Value& peg_names);
+ bool confirm_parse();
+ bool resolve();
- int perf_flags;
- uint32_t pkt_cnt;
- int sample_interval;
- uint64_t max_file_size;
- int flow_max_port_to_track;
- uint32_t flowip_memcap;
- PerfFormat format;
- PerfOutput output;
+private:
+ std::string name;
+ std::unordered_map<std::string, bool> peg_names;
};
-struct PerfConfig:public PerfConfigBase
+struct PerfConfig
{
- std::vector<snort::Module*> modules;
- std::vector<IndexVec> mod_peg_idxs;
+ int perf_flags = 0;
+ uint32_t pkt_cnt = 0;
+ int sample_interval = 0;
+ uint64_t max_file_size = 0;
+ int flow_max_port_to_track = 0;
+ uint32_t flowip_memcap = 0;
+ PerfFormat format = PerfFormat::CSV;
+ PerfOutput output = PerfOutput::TO_FILE;
+ std::vector<ModuleConfig> modules;
+
+ bool resolve();
};
/* The Module Class for incorporation into Snort++ */
PegCount* get_counts() const override;
snort::ProfileStats* get_profile() const override;
- void get_config(PerfConfig&);
+ PerfConfig& get_config();
Usage get_usage() const override
- { return CONTEXT; }
+ { return GLOBAL; }
private:
PerfConfig config;
-
- std::string mod_pegs;
- std::string mod_name;
};
extern THREAD_LOCAL SimpleStats pmstats;
#include "config.h"
#endif
-#include "perf_monitor.h"
-
+#include "framework/data_bus.h"
#include "log/messages.h"
#include "managers/inspector_manager.h"
#include "profiler/profiler.h"
#include "cpu_tracker.h"
#include "flow_ip_tracker.h"
#include "flow_tracker.h"
+#include "perf_module.h"
#ifdef UNIT_TEST
#include "catch/snort_catch.h"
THREAD_LOCAL SimpleStats pmstats;
THREAD_LOCAL ProfileStats perfmonStats;
-THREAD_LOCAL bool perfmon_rotate_perf_file = false;
-static PerfConfig config;
-PerfConfig* perfmon_config = &config; // FIXIT-M remove this after flowip can be decoupled.
static THREAD_LOCAL std::vector<PerfTracker*>* trackers;
-static bool ready_to_process(Packet* p);
-
//-------------------------------------------------------------------------
// class stuff
//-------------------------------------------------------------------------
+class PerfIdleHandler;
+class PerfRotateHandler;
class PerfMonitor : public Inspector
{
public:
void show(SnortConfig*) override;
void eval(Packet*) override;
+ bool ready_to_process(Packet* p);
void tinit() override;
void tterm() override;
+
+ void rotate();
+private:
+ PerfConfig& config;
+ PerfIdleHandler* idle_handler = nullptr;
+ PerfRotateHandler* rotate_handler = nullptr;
+};
+
+class PerfIdleHandler : public DataHandler
+{
+public:
+ PerfIdleHandler(PerfMonitor& p) : perf_monitor(p)
+ { DataBus::subscribe_default(THREAD_IDLE_EVENT, this); }
+
+ virtual void handle(DataEvent&, Flow*) override
+ { perf_monitor.eval(nullptr); }
+
+private:
+ PerfMonitor& perf_monitor;
};
-PerfMonitor::PerfMonitor(PerfMonModule* mod)
+class PerfRotateHandler : public DataHandler
{
- mod->get_config(config);
- perfmon_config = &config;
+public:
+ PerfRotateHandler(PerfMonitor& p) : perf_monitor(p)
+ { DataBus::subscribe_default(THREAD_ROTATE_EVENT, this); }
+
+ virtual void handle(DataEvent&, Flow*) override
+ { perf_monitor.rotate(); }
+
+private:
+ PerfMonitor& perf_monitor;
+};
+
+PerfMonitor::PerfMonitor(PerfMonModule* mod) : config(mod->get_config())
+{
+ idle_handler = new PerfIdleHandler(*this);
+ rotate_handler = new PerfRotateHandler(*this);
}
void PerfMonitor::show(SnortConfig*)
}
LogMessage(" CPU Stats: %s\n",
(config.perf_flags & PERF_CPU) ? "ACTIVE" : "INACTIVE");
- switch(config.output)
+ switch ( config.output )
{
- case PERF_CONSOLE:
+ case PerfOutput::TO_CONSOLE:
LogMessage(" Output Location: console\n");
break;
- case PERF_FILE:
+ case PerfOutput::TO_FILE:
LogMessage(" Output Location: file\n");
break;
}
switch(config.format)
{
- case PERF_TEXT:
+ case PerfFormat::TEXT:
LogMessage(" Output Format: text\n");
break;
- case PERF_CSV:
+ case PerfFormat::CSV:
LogMessage(" Output Format: csv\n");
break;
- case PERF_JSON:
+ case PerfFormat::JSON:
LogMessage(" Output Format: json\n");
break;
#ifdef HAVE_FLATBUFFERS
- case PERF_FBS:
+ case PerfFormat::FBS:
LogMessage(" Output Format: flatbuffers\n");
break;
#endif
bool PerfMonitor::configure(SnortConfig*)
{
- return true;
+ idle_handler = new PerfIdleHandler(*this);
+ rotate_handler = new PerfRotateHandler(*this);
+
+ return config.resolve();
}
void PerfMonitor::tinit()
trackers->push_back(new FlowTracker(&config));
if (config.perf_flags & PERF_FLOWIP)
- trackers->push_back(perf_flow_ip = new FlowIPTracker(&config));
+ trackers->push_back(new FlowIPTracker(&config));
if (config.perf_flags & PERF_CPU )
trackers->push_back(new CPUTracker(&config));
void PerfMonitor::tterm()
{
- perf_flow_ip = nullptr;
-
if (trackers)
{
while (!trackers->empty())
}
}
+void PerfMonitor::rotate()
+{
+ for ( unsigned i = 0; i < trackers->size(); i++ )
+ if ( !(*trackers)[i]->rotate() )
+ disable_tracker(i--);
+}
+
void PerfMonitor::eval(Packet* p)
{
Profile profile(perfmonStats);
- if (IsSetRotatePerfFileFlag())
- {
- for (unsigned i = 0; i < trackers->size(); i++)
- {
- if (!(*trackers)[i]->rotate())
- disable_tracker(i--);
- }
-
- ClearRotatePerfFileFlag();
- }
-
if (p)
{
for (auto& tracker : *trackers)
++pmstats.total_packets;
}
-//FIXIT-M uncouple from Snort class when framework permits
-void perf_monitor_idle_process()
-{
- PerfMonitor* pm =
- (PerfMonitor*)InspectorManager::get_inspector("perf_monitor", true);
-
- if ( pm )
- pm->eval(nullptr);
-}
-
-static bool ready_to_process(Packet* p)
+bool PerfMonitor::ready_to_process(Packet* p)
{
static THREAD_LOCAL time_t sample_time = 0;
static THREAD_LOCAL time_t cur_time = 0;
nullptr // reset
};
-const BaseApi* nin_perf_monitor = &pm_api.base;
+#ifdef BUILDING_SO
+SO_PUBLIC const BaseApi* snort_plugins[] =
+#else
+const BaseApi* nin_perf_monitor[] =
+#endif
+{
+ &pm_api.base,
+ nullptr
+};
#ifdef UNIT_TEST
TEST_CASE("Process timing logic", "[perfmon]")
{
+ PerfMonModule mod;
+ PerfConfig& config = mod.get_config();
+ PerfMonitor perfmon(&mod);
+
Packet p(false);
DAQ_PktHdr_t pkth;
p.pkth = &pkth;
config.pkt_cnt = 0;
config.sample_interval = 0;
pkth.ts.tv_sec = 0;
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
pkth.ts.tv_sec = 1;
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
config.pkt_cnt = 2;
config.sample_interval = 0;
pkth.ts.tv_sec = 2;
- REQUIRE((ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 3;
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
config.pkt_cnt = 0;
config.sample_interval = 2;
pkth.ts.tv_sec = 4;
- REQUIRE((ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 8;
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
pkth.ts.tv_sec = 10;
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
config.pkt_cnt = 5;
config.sample_interval = 4;
pkth.ts.tv_sec = 11;
- REQUIRE((ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 14;
- REQUIRE((ready_to_process(&p) == false));
- REQUIRE((ready_to_process(&p) == false));
- REQUIRE((ready_to_process(&p) == false));
- REQUIRE((ready_to_process(&p) == true));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == false));
+ REQUIRE((perfmon.ready_to_process(&p) == true));
}
#endif
+++ /dev/null
-//--------------------------------------------------------------------------
-// Copyright (C) 2014-2018 Cisco and/or its affiliates. All rights reserved.
-// Copyright (C) 2002-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.
-//--------------------------------------------------------------------------
-// perf_monitor.h author Carter Waxman <cwaxman@cisco.com>
-
-#ifndef PERF_MONITOR_H
-#define PERF_MONITOR_H
-
-// These are the basic functions and structures that are needed to call
-// performance functions.
-
-#include "perf_module.h"
-
-namespace snort
-{
-struct Packet;
-}
-
-extern PerfConfig* perfmon_config; // FIXIT-M shouldn't be needed externally
-extern THREAD_LOCAL bool perfmon_rotate_perf_file;
-
-void perf_monitor_idle_process();
-
-/* functions to set & get the RotatePerfFileFlag */
-inline void SetRotatePerfFileFlag()
-{
- perfmon_rotate_perf_file = true;
-}
-
-inline bool IsSetRotatePerfFileFlag()
-{
- return perfmon_rotate_perf_file;
-}
-
-inline void ClearRotatePerfFileFlag()
-{
- perfmon_rotate_perf_file = false;
-}
-
-#endif
-
return false;
}
-PerfTracker::PerfTracker(PerfConfig* config, bool file, const char* tracker_name)
+PerfTracker::PerfTracker(PerfConfig* config, const char* tracker_name)
{
this->config = config;
switch (config->format)
{
- case PERF_CSV: formatter = new CSVFormatter(tracker_name); break;
- case PERF_TEXT: formatter = new TextFormatter(tracker_name); break;
- case PERF_JSON: formatter = new JSONFormatter(tracker_name); break;
+ case PerfFormat::CSV: formatter = new CSVFormatter(tracker_name); break;
+ case PerfFormat::TEXT: formatter = new TextFormatter(tracker_name); break;
+ case PerfFormat::JSON: formatter = new JSONFormatter(tracker_name); break;
#ifdef HAVE_FLATBUFFERS
- case PERF_FBS: formatter = new FbsFormatter(tracker_name); break;
+ case PerfFormat::FBS: formatter = new FbsFormatter(tracker_name); break;
#endif
#ifdef UNIT_TEST
- case PERF_MOCK: formatter = new MockFormatter(tracker_name); break;
+ case PerfFormat::MOCK: formatter = new MockFormatter(tracker_name); break;
#endif
default: break;
}
- if (file)
+ if ( config->output == PerfOutput::TO_FILE )
{
string tracker_fname = tracker_name;
tracker_fname += formatter->get_extension();
#include <ctime>
#include "perf_formatter.h"
-#include "perf_monitor.h"
+#include "perf_module.h"
+namespace snort
+{
+ class Packet;
+}
class PerfTracker
{
public:
PerfConfig* config;
PerfFormatter* formatter;
- PerfTracker(PerfConfig*, bool file, const char* tracker_name);
+ PerfTracker(PerfConfig*, const char* tracker_name);
virtual void write() final;
private:
PortscanConfig* get_data();
Usage get_usage() const override
- { return CONTEXT; }
+ { return GLOBAL; } // FIXIT-M this should eventually be CONTEXT.
+ // Set to GLOBAL so this isn't selected away when inspection policy switches
private:
PS_ALERT_CONF* get_alert_conf(const char* fqn);
#ifndef TCP_DEBUG_TRACE_H
#define TCP_DEBUG_TRACE_H
-#include "stream/tcp/tcp_reassembler.h"
+#include "utils/stats.h"
+
+#include "tcp_reassembler.h"
#ifndef REG_TEST
#define S5TraceTCP(pkt, flow, tsd, evt)
uint32_t rack = ( rxd ) ? h->ack() - rxd : h->ack();
fprintf(stdout, "\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4hu Len=%-4hu%s\n",
//"\n" FMTu64("-3") " %s=0x%02x Seq=%-4u Ack=%-4u Win=%-4u Len=%-4u End=%-4u%s\n",
- pc.total_from_daq, flags, h->th_flags, rseq, rack, h->win(), p->dsize, order);
+ get_packet_number(), flags, h->th_flags, rseq, rack, h->win(), p->dsize, order);
}
inline void TraceSession(const snort::Flow* lws)
#include "detection/detection_engine.h"
#include "detection/rules.h"
#include "log/log.h"
-#include "perf_monitor/flow_ip_tracker.h"
#include "profiler/profiler.h"
#include "protocols/eth.h"
void TcpSession::update_perf_base_state(char newState)
{
uint32_t session_flags = flow->get_session_flags();
+ bool fire_event = false;
+
switch ( newState )
{
case TcpStreamTracker::TCP_SYN_SENT:
if ( !( session_flags & SSNFLAG_COUNTED_ESTABLISH ) )
{
tcpStats.sessions_established++;
- if ( perfmon_config && ( perfmon_config->perf_flags & PERF_FLOWIP ) )
- perf_flow_ip->update_state(&flow->client_ip,
- &flow->server_ip, SFS_STATE_TCP_ESTABLISHED);
-
session_flags |= SSNFLAG_COUNTED_ESTABLISH;
+ fire_event = true;
+
tel.log_internal_event(INTERNAL_EVENT_SESSION_ADD);
if ( ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
&& !( session_flags & SSNFLAG_COUNTED_CLOSING ) )
{
assert(tcpStats.sessions_established);
tcpStats.sessions_established--;
-
- if (perfmon_config && (perfmon_config->perf_flags & PERF_FLOWIP))
- perf_flow_ip->update_state(&flow->client_ip, &flow->server_ip,
- SFS_STATE_TCP_CLOSED);
}
else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
{
if ( !( session_flags & SSNFLAG_COUNTED_CLOSED ) )
{
session_flags |= SSNFLAG_COUNTED_CLOSED;
+ fire_event = true;
if ( session_flags & SSNFLAG_COUNTED_CLOSING )
{
{
assert(tcpStats.sessions_established);
tcpStats.sessions_established--;
-
- if ( perfmon_config && ( perfmon_config->perf_flags & PERF_FLOWIP ) )
- perf_flow_ip->update_state(&flow->client_ip,
- &flow->server_ip, SFS_STATE_TCP_CLOSED);
}
else if ( session_flags & SSNFLAG_COUNTED_INITIALIZE )
{
}
flow->update_session_flags(session_flags);
+
+ if ( fire_event )
+ DataBus::publish(FLOW_STATE_EVENT, nullptr, flow);
}
bool TcpSession::flow_exceeds_config_thresholds(TcpSegmentDescriptor& tsd)
#include "udp_session.h"
#include "flow/session.h"
-#include "perf_monitor/flow_ip_tracker.h"
+#include "framework/data_bus.h"
+#include "hash/xhash.h"
#include "profiler/profiler_defs.h"
#include "protocols/packet.h"
SESSION_STATS_ADD(udpStats);
- if (perfmon_config && (perfmon_config->perf_flags & PERF_FLOWIP))
- {
- perf_flow_ip->update_state(&flow->client_ip,
- &flow->server_ip, SFS_STATE_UDP_CREATED);
- }
+ DataBus::publish(FLOW_STATE_EVENT, p);
if ( Stream::expected_flow(flow, p) )
{