#include "config.h"
#endif
-#ifdef HAVE_FLATBUFFERS
-#define FLATBUFFERS_ENUM " | flatbuffers"
-#else
-#define FLATBUFFERS_ENUM
-#endif
-
#include "perf_module.h"
+#include <lua.hpp>
+
#include "log/messages.h"
+#include "main/analyzer_command.h"
#include "main/snort.h"
#include "managers/module_manager.h"
+#include "perf_monitor.h"
#include "perf_pegs.h"
#include "perf_reload_tuner.h"
+#ifdef HAVE_FLATBUFFERS
+#define FLATBUFFERS_ENUM " | flatbuffers"
+#else
+#define FLATBUFFERS_ENUM
+#endif
+
using namespace snort;
//-------------------------------------------------------------------------
{ nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
};
+class PerfMonFlowIPDebug : public AnalyzerCommand
+{
+public:
+ PerfMonFlowIPDebug(PerfConstraints* cs, bool en, PerfMonitor* pm) :
+ enable(en), constraints(cs), perf_monitor(pm) { }
+ ~PerfMonFlowIPDebug() override
+ { perf_monitor->swap_constraints(constraints); }
+
+ bool execute(Analyzer&, void**) override;
+ const char* stringify() override { return "FLOW_IP_PROFILING"; }
+
+private:
+ bool enable;
+ PerfConstraints* constraints;
+ PerfMonitor* perf_monitor;
+};
+
+static const Parameter flow_ip_profiling_params[] =
+{
+ { "seconds", Parameter::PT_INT, "1:max32", nullptr,
+ "report interval" },
+
+ { "packets", Parameter::PT_INT, "0:max32", nullptr,
+ "minimum packets to report" },
+
+ { nullptr, Parameter::PT_MAX, nullptr, nullptr, nullptr }
+};
+
+bool PerfMonFlowIPDebug::execute(Analyzer&, void**)
+{
+ if (enable)
+ perf_monitor->enable_profiling(constraints);
+ else
+ perf_monitor->disable_profiling(constraints);
+
+ return true;
+}
+
+static int enable_flow_ip_profiling(lua_State* L)
+{
+ PerfMonitor* perf_monitor =
+ (PerfMonitor*)InspectorManager::get_inspector(PERF_NAME, true);
+
+ if (!perf_monitor)
+ {
+ LogMessage("perf_monitor is not configured, "
+ "flow ip profiling cannot be enabled.\n");
+ return 0;
+ }
+
+ auto* new_constraints = new PerfConstraints(true, luaL_optint(L, 1, 0),
+ luaL_optint(L, 2, 0));
+
+ main_broadcast_command(new PerfMonFlowIPDebug(new_constraints, true, perf_monitor),
+ true);
+
+ LogMessage("Enabling flow ip profiling with sample interval %d packet count %d\n",
+ new_constraints->sample_interval, new_constraints->pkt_cnt);
+
+ return 0;
+}
+
+static int disable_flow_ip_profiling(lua_State*)
+{
+ PerfMonitor* perf_monitor =
+ (PerfMonitor*)InspectorManager::get_inspector(PERF_NAME, true);
+
+ if (!perf_monitor)
+ {
+ LogMessage("Attempting to disable flow ip profiling when "
+ "perf_monitor is not configured\n");
+ return 0;
+ }
+
+ if (!perf_monitor->is_flow_ip_enabled())
+ {
+ LogMessage("Attempting to disable flow ip profiling when "
+ "it is not running\n");
+ return 0;
+ }
+
+ auto* new_constraints = perf_monitor->get_original_constraints();
+
+ main_broadcast_command(new PerfMonFlowIPDebug(new_constraints, false, perf_monitor),
+ true);
+
+ LogMessage("Disabling flow ip profiling\n");
+
+ return 0;
+}
+
+static int show_flow_ip_profiling(lua_State*)
+{
+ bool status = false;
+
+ PerfMonitor* perf_monitor = (PerfMonitor*)InspectorManager::get_inspector(PERF_NAME, true);
+
+ if (perf_monitor)
+ status = perf_monitor->is_flow_ip_enabled();
+ else
+ LogMessage("perf_monitor is not configured\n");
+
+ LogMessage("Snort flow ip profiling is %s\n", status ? "enabled" : "disabled");
+
+ return 0;
+}
+
+static const Command perf_module_cmds[] =
+{
+ { "enable_flow_ip_profiling", enable_flow_ip_profiling,
+ flow_ip_profiling_params, "enable statistics on host pairs" },
+
+ { "disable_flow_ip_profiling", disable_flow_ip_profiling,
+ nullptr, "disable statistics on host pairs" },
+
+ { "show_flow_ip_profiling", show_flow_ip_profiling,
+ nullptr, "show status of statistics on host pairs" },
+
+ { nullptr, nullptr, nullptr, nullptr }
+};
+
//-------------------------------------------------------------------------
// perf attributes
//-------------------------------------------------------------------------
PerfConfig* PerfMonModule::get_config()
{
PerfConfig* tmp = config;
+
+ tmp->constraints->flow_ip_enabled = config->perf_flags & PERF_FLOWIP;
+ tmp->constraints->sample_interval = config->sample_interval;
+ tmp->constraints->pkt_cnt = config->pkt_cnt;
+
config = nullptr;
return tmp;
}
PegCount* PerfMonModule::get_counts() const
{ return (PegCount*)&pmstats; }
+const Command* PerfMonModule::get_commands() const
+{ return perf_module_cmds; }
+
void ModuleConfig::set_name(const std::string& name)
{ this->name = name; }
std::unordered_map<std::string, bool> peg_names;
};
+struct PerfConstraints
+{
+ bool flow_ip_enabled = false;
+ unsigned sample_interval = 0;
+ uint32_t pkt_cnt = 0;
+
+ PerfConstraints() = default;
+ PerfConstraints(bool en, unsigned interval, uint32_t cnt) :
+ flow_ip_enabled(en), sample_interval(interval), pkt_cnt(cnt) { }
+};
+
struct PerfConfig
{
int perf_flags = 0;
PerfOutput output = PerfOutput::TO_FILE;
std::vector<ModuleConfig> modules;
std::vector<snort::Module*> mods_to_prep;
+ PerfConstraints* constraints;
+
+ PerfConfig() { constraints = new PerfConstraints; }
+ ~PerfConfig() { delete constraints; }
bool resolve();
};
PerfMonModule();
~PerfMonModule() override;
+ const snort::Command* get_commands() const override;
bool set(const char*, snort::Value&, snort::SnortConfig*) override;
bool begin(const char*, int, snort::SnortConfig*) override;
bool end(const char*, int, snort::SnortConfig*) override;
#include "config.h"
#endif
+#include "perf_monitor.h"
+
#include "framework/data_bus.h"
#include "hash/hash_defs.h"
#include "hash/xhash.h"
#include "log/messages.h"
-#include "managers/inspector_manager.h"
+#include "main/analyzer_command.h"
+#include "main/thread.h"
#include "profiler/profiler.h"
#include "protocols/packet.h"
-#include "base_tracker.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"
#endif
static THREAD_LOCAL std::vector<PerfTracker*>* trackers;
static THREAD_LOCAL FlowIPTracker* flow_ip_tracker = nullptr;
+static THREAD_LOCAL PerfConstraints* t_constraints;
+
//-------------------------------------------------------------------------
// class stuff
//-------------------------------------------------------------------------
-class FlowIPDataHandler;
-class PerfMonitor : public Inspector
-{
-public:
- PerfMonitor(PerfConfig*);
- ~PerfMonitor() override { delete config;}
-
- bool configure(SnortConfig*) override;
- void show(SnortConfig*) override;
-
- void eval(Packet*) override;
- bool ready_to_process(Packet* p);
-
- void tinit() override;
- void tterm() override;
-
- void rotate();
-
- FlowIPTracker* get_flow_ip();
-
-private:
- PerfConfig* const config;
- void disable_tracker(size_t);
-};
-
class PerfIdleHandler : public DataHandler
{
public:
void handle(DataEvent&, Flow* flow) override
{
+ FlowIPTracker* tracker = perf_monitor.get_flow_ip();
+
+ if (!tracker)
+ return;
+
FlowState state = SFS_STATE_MAX;
if ( flow->pkt_type == PktType::UDP )
if ( state == SFS_STATE_MAX )
return;
- FlowIPTracker* tracker = perf_monitor.get_flow_ip();
- if (tracker)
- tracker->update_state(&flow->client_ip, &flow->server_ip, state);
+ tracker->update_state(&flow->client_ip, &flow->server_ip, state);
}
private:
{
new PerfIdleHandler(*this, sc);
new PerfRotateHandler(*this, sc);
-
- if ( config->perf_flags & PERF_FLOWIP )
- new FlowIPDataHandler(*this, sc);
+ new FlowIPDataHandler(*this, sc);
return config->resolve();
}
{
trackers = new std::vector<PerfTracker*>();
+ t_constraints = config->constraints;
+
if (config->perf_flags & PERF_BASE)
trackers->emplace_back(new BaseTracker(config));
if (config->perf_flags & PERF_FLOW)
trackers->emplace_back(new FlowTracker(config));
+ flow_ip_tracker = new FlowIPTracker(config);
if (config->perf_flags & PERF_FLOWIP)
- {
- flow_ip_tracker = new FlowIPTracker(config);
trackers->emplace_back(flow_ip_tracker);
- }
if (config->perf_flags & PERF_CPU )
trackers->emplace_back(new CPUTracker(config));
bool PerfMonReloadTuner::tinit()
{
- if (flow_ip_tracker)
+ PerfMonitor* pm = (PerfMonitor*)InspectorManager::get_inspector(PERF_NAME, true);
+ auto* new_constraints = pm->get_constraints();
+
+ if (new_constraints->flow_ip_enabled)
+ {
+ pm->enable_profiling(new_constraints);
return flow_ip_tracker->initialize(memcap);
+ }
else
- return false;
+ pm->disable_profiling(new_constraints);
+
+ return false;
}
bool PerfMonReloadTuner::tune_resources(unsigned work_limit)
{
- if (flow_ip_tracker)
+ if (t_constraints->flow_ip_enabled)
{
unsigned num_freed = 0;
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
- return true;
+
+ return true;
}
void PerfMonitor::tterm()
auto back = trackers->back();
if ( config->perf_flags & PERF_SUMMARY )
back->process(true);
+ if (back == flow_ip_tracker)
+ flow_ip_tracker = nullptr;
delete back;
trackers->pop_back();
}
delete trackers;
- flow_ip_tracker = nullptr;
+ if (flow_ip_tracker)
+ {
+ delete flow_ip_tracker;
+ flow_ip_tracker = nullptr;
+ }
}
}
disable_tracker(i--);
}
+void PerfMonitor::swap_constraints(PerfConstraints* constraints)
+{
+ PerfConstraints* tmp = config->constraints;
+
+ config->constraints = constraints;
+ delete tmp;
+}
+
+PerfConstraints* PerfMonitor::get_original_constraints()
+{
+ auto* new_constraints = new PerfConstraints(false, config->pkt_cnt,
+ config->sample_interval);
+
+ return new_constraints;
+}
+
+void PerfMonitor::enable_profiling(PerfConstraints* constraints)
+{
+ t_constraints = constraints;
+
+ auto itr = std::find(trackers->begin(), trackers->end(), flow_ip_tracker);
+
+ if (itr != trackers->end())
+ return;
+
+ trackers->emplace_back(flow_ip_tracker);
+
+ if (!flow_ip_tracker->is_open())
+ flow_ip_tracker->open(true);
+}
+
+void PerfMonitor::disable_profiling(PerfConstraints* constraints)
+{
+ t_constraints = constraints;
+
+ auto itr = std::find(trackers->begin(), trackers->end(), flow_ip_tracker);
+
+ if (itr != trackers->end())
+ {
+ trackers->erase(itr);
+ flow_ip_tracker->close();
+ }
+}
+
void PerfMonitor::eval(Packet* p)
{
Profile profile(perfmonStats);
if (!sample_time)
sample_time = cur_time;
- if ( cnt >= config->pkt_cnt )
+ if ( cnt >= t_constraints->pkt_cnt )
{
- if ((cur_time - sample_time) >= config->sample_interval)
+ if ((cur_time - sample_time) >= t_constraints->sample_interval)
{
if (cnt == 0)
for (auto& tracker : *trackers)
}
FlowIPTracker* PerfMonitor::get_flow_ip()
-{ return flow_ip_tracker; }
+{ return t_constraints->flow_ip_enabled ? flow_ip_tracker : nullptr; }
//-------------------------------------------------------------------------
// api stuff
DAQ_PktHdr_t pkth;
p.pkth = &pkth;
- config->pkt_cnt = 0;
- config->sample_interval = 0;
+ t_constraints = config->constraints;
+
+ t_constraints->pkt_cnt = 0;
+ t_constraints->sample_interval = 0;
pkth.ts.tv_sec = 0;
REQUIRE((perfmon.ready_to_process(&p) == true));
pkth.ts.tv_sec = 1;
REQUIRE((perfmon.ready_to_process(&p) == true));
- config->pkt_cnt = 2;
- config->sample_interval = 0;
+ t_constraints->pkt_cnt = 2;
+ t_constraints->sample_interval = 0;
pkth.ts.tv_sec = 2;
REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 3;
REQUIRE((perfmon.ready_to_process(&p) == true));
- config->pkt_cnt = 0;
- config->sample_interval = 2;
+ t_constraints->pkt_cnt = 0;
+ t_constraints->sample_interval = 2;
pkth.ts.tv_sec = 4;
REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 8;
pkth.ts.tv_sec = 10;
REQUIRE((perfmon.ready_to_process(&p) == true));
- config->pkt_cnt = 5;
- config->sample_interval = 4;
+ t_constraints->pkt_cnt = 5;
+ t_constraints->sample_interval = 4;
pkth.ts.tv_sec = 11;
REQUIRE((perfmon.ready_to_process(&p) == false));
pkth.ts.tv_sec = 14;
--- /dev/null
+//--------------------------------------------------------------------------
+// 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.
+//--------------------------------------------------------------------------
+
+// perf_monitor.h author Puneeth Kumar C V <puneetku@cisco.com>
+
+#ifndef PERF_MONITOR_H
+#define PERF_MONITOR_H
+
+#include "managers/inspector_manager.h"
+#include "protocols/packet.h"
+
+#include "base_tracker.h"
+#include "cpu_tracker.h"
+#include "flow_ip_tracker.h"
+#include "flow_tracker.h"
+#include "perf_module.h"
+
+class FlowIPDataHandler;
+
+class PerfMonitor : public snort::Inspector
+{
+public:
+ PerfMonitor(PerfConfig*);
+ ~PerfMonitor() override { delete config; }
+
+ bool configure(snort::SnortConfig*) override;
+ void show(snort::SnortConfig*) override;
+
+ void eval(snort::Packet*) override;
+ bool ready_to_process(snort::Packet* p);
+
+ void tinit() override;
+ void tterm() override;
+
+ void rotate();
+
+ void swap_constraints(PerfConstraints*);
+ PerfConstraints* get_original_constraints();
+
+ void enable_profiling(PerfConstraints*);
+ void disable_profiling(PerfConstraints*);
+
+ FlowIPTracker* get_flow_ip();
+
+ inline PerfConstraints* get_constraints()
+ { return config->constraints; }
+
+ inline bool is_flow_ip_enabled()
+ { return config->constraints->flow_ip_enabled; }
+
+private:
+ PerfConfig* const config;
+ void disable_tracker(size_t);
+};
+
+#endif
+
fclose(fh);
}
+void PerfTracker::close()
+{
+ if (fh && fh != stdout)
+ {
+ fclose(fh);
+ fh = nullptr;
+ }
+}
+
bool PerfTracker::open(bool append)
{
if (fname.length())
class PerfTracker
{
public:
- virtual void reset() {}
-
- virtual void update(snort::Packet*) {}
- virtual void process(bool /*summary*/) {} // FIXIT-M get rid of this step.
+ virtual ~PerfTracker();
- virtual void update_time(time_t time) final { cur_time = time; }
- virtual const std::string& get_name() final { return tracker_name; }
+ virtual void reset() { }
+ virtual void process(bool /*summary*/) { } // FIXIT-M get rid of this step.
+ virtual void update(snort::Packet*) { }
+ virtual void update_time(time_t time) { cur_time = time; }
+ virtual const std::string& get_name() { return tracker_name; }
- virtual bool open(bool append) final;
- virtual bool rotate() final;
- virtual bool auto_rotate() final;
-
- virtual ~PerfTracker();
+ bool open(bool append);
+ void close();
+ bool rotate();
+ bool auto_rotate();
+ bool is_open() { return fh != nullptr; }
PerfTracker(const PerfTracker&) = delete;
PerfTracker& operator=(const PerfTracker&) = delete;
protected:
- uint64_t max_file_size = 0;
+ PerfTracker(PerfConfig*, const char* tracker_name);
+ virtual void write();
+ uint64_t max_file_size = 0;
PerfFormatter* formatter;
- PerfTracker(PerfConfig*, const char* tracker_name);
- virtual void write() final;
-
private:
std::string fname;
std::string tracker_name;