From: Russ Combs (rucombs) Date: Thu, 9 Apr 2020 03:43:45 +0000 (+0000) Subject: Merge pull request #2086 in SNORT/snort3 from ~PUNEETKU/snort3:pm_shell_cmd to master X-Git-Tag: 3.0.1-2~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=89dfdb12b7f2f089a967be2f7cbbd500354c7371;p=thirdparty%2Fsnort3.git Merge pull request #2086 in SNORT/snort3 from ~PUNEETKU/snort3:pm_shell_cmd to master Squashed commit of the following: commit 2b6c7588e78aac9e3a0a31b0b1571095b25c80ad Author: Puneeth Kumar C V Date: Sun Mar 15 22:52:53 2020 -0400 perf_monitor: Enable or disable flow-ip-profiling using shell commands --- diff --git a/src/network_inspectors/perf_monitor/perf_module.cc b/src/network_inspectors/perf_monitor/perf_module.cc index 4b215808c..37296417d 100644 --- a/src/network_inspectors/perf_monitor/perf_module.cc +++ b/src/network_inspectors/perf_monitor/perf_module.cc @@ -22,21 +22,25 @@ #include "config.h" #endif -#ifdef HAVE_FLATBUFFERS -#define FLATBUFFERS_ENUM " | flatbuffers" -#else -#define FLATBUFFERS_ENUM -#endif - #include "perf_module.h" +#include + #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; //------------------------------------------------------------------------- @@ -98,6 +102,127 @@ static const Parameter s_params[] = { 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 //------------------------------------------------------------------------- @@ -224,6 +349,11 @@ bool PerfMonModule::end(const char* fqn, int idx, SnortConfig* sc) 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; } @@ -234,6 +364,9 @@ const PegInfo* PerfMonModule::get_pegs() const 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; } diff --git a/src/network_inspectors/perf_monitor/perf_module.h b/src/network_inspectors/perf_monitor/perf_module.h index 1bcd8f139..02f446a13 100644 --- a/src/network_inspectors/perf_monitor/perf_module.h +++ b/src/network_inspectors/perf_monitor/perf_module.h @@ -76,6 +76,17 @@ private: std::unordered_map 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; @@ -88,6 +99,10 @@ struct PerfConfig PerfOutput output = PerfOutput::TO_FILE; std::vector modules; std::vector mods_to_prep; + PerfConstraints* constraints; + + PerfConfig() { constraints = new PerfConstraints; } + ~PerfConfig() { delete constraints; } bool resolve(); }; @@ -99,6 +114,7 @@ public: 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; diff --git a/src/network_inspectors/perf_monitor/perf_monitor.cc b/src/network_inspectors/perf_monitor/perf_monitor.cc index 8c038418f..d18ffdddd 100644 --- a/src/network_inspectors/perf_monitor/perf_monitor.cc +++ b/src/network_inspectors/perf_monitor/perf_monitor.cc @@ -28,21 +28,17 @@ #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 @@ -55,35 +51,12 @@ THREAD_LOCAL ProfileStats perfmonStats; static THREAD_LOCAL std::vector* 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: @@ -118,6 +91,11 @@ 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 ) @@ -135,9 +113,7 @@ public: 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: @@ -222,9 +198,7 @@ bool PerfMonitor::configure(SnortConfig* sc) { 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(); } @@ -233,17 +207,17 @@ void PerfMonitor::tinit() { trackers = new std::vector(); + 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)); @@ -260,23 +234,31 @@ void PerfMonitor::tinit() 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() @@ -288,11 +270,17 @@ 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; + } } } @@ -303,6 +291,50 @@ void PerfMonitor::rotate() 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); @@ -355,9 +387,9 @@ bool PerfMonitor::ready_to_process(Packet* p) 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) @@ -372,7 +404,7 @@ bool PerfMonitor::ready_to_process(Packet* p) } FlowIPTracker* PerfMonitor::get_flow_ip() -{ return flow_ip_tracker; } +{ return t_constraints->flow_ip_enabled ? flow_ip_tracker : nullptr; } //------------------------------------------------------------------------- // api stuff @@ -440,22 +472,24 @@ TEST_CASE("Process timing logic", "[perfmon]") 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; @@ -463,8 +497,8 @@ TEST_CASE("Process timing logic", "[perfmon]") 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; diff --git a/src/network_inspectors/perf_monitor/perf_monitor.h b/src/network_inspectors/perf_monitor/perf_monitor.h new file mode 100644 index 000000000..4f8cb3f2c --- /dev/null +++ b/src/network_inspectors/perf_monitor/perf_monitor.h @@ -0,0 +1,72 @@ +//-------------------------------------------------------------------------- +// 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 + +#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 + diff --git a/src/network_inspectors/perf_monitor/perf_tracker.cc b/src/network_inspectors/perf_monitor/perf_tracker.cc index 9e51d5dd0..cc9efa409 100644 --- a/src/network_inspectors/perf_monitor/perf_tracker.cc +++ b/src/network_inspectors/perf_monitor/perf_tracker.cc @@ -97,6 +97,15 @@ PerfTracker::~PerfTracker() fclose(fh); } +void PerfTracker::close() +{ + if (fh && fh != stdout) + { + fclose(fh); + fh = nullptr; + } +} + bool PerfTracker::open(bool append) { if (fname.length()) diff --git a/src/network_inspectors/perf_monitor/perf_tracker.h b/src/network_inspectors/perf_monitor/perf_tracker.h index d27d60a35..168628748 100644 --- a/src/network_inspectors/perf_monitor/perf_tracker.h +++ b/src/network_inspectors/perf_monitor/perf_tracker.h @@ -51,31 +51,30 @@ struct Packet; 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;