From: Shanmugam S (shanms) Date: Fri, 24 Mar 2023 08:10:12 +0000 (+0000) Subject: Pull request #3787: flow_cache: Prune multiple flows X-Git-Tag: 3.1.59.0~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a192c18a848f4df97bf00e16a97c2027ec65e61b;p=thirdparty%2Fsnort3.git Pull request #3787: flow_cache: Prune multiple flows Merge in SNORT/snort3 from ~KBHANDAN/snort3:prune_multiple to master Squashed commit of the following: commit 2851a29722b096be89b291dc8d2e88dd0764510b Author: Kaushal Bhandankar Date: Thu Mar 23 01:28:22 2023 +0530 flow_cache: Prune multiple flows --- diff --git a/src/flow/flow_cache.cc b/src/flow/flow_cache.cc index bdadac13d..39fbce641 100644 --- a/src/flow/flow_cache.cc +++ b/src/flow/flow_cache.cc @@ -354,8 +354,7 @@ unsigned FlowCache::prune_excess(const Flow* save_me) if (!pruned and hash_table->get_num_nodes() > max_cap) { - prune_one(PruneReason::EXCESS, true); - ++pruned; + pruned += prune_multiple(PruneReason::EXCESS, true); } } @@ -381,6 +380,21 @@ bool FlowCache::prune_one(PruneReason reason, bool do_cleanup) return true; } +unsigned FlowCache::prune_multiple(PruneReason reason, bool do_cleanup) +{ + unsigned pruned = 0; + // so we don't prune the current flow (assume current == MRU) + if ( hash_table->get_num_nodes() <= 1 ) + return 0; + + for (pruned = 0; pruned < config.prune_flows && prune_one(reason, do_cleanup); pruned++); + + if ( PacketTracer::is_active() and pruned ) + PacketTracer::log("Flow: Pruned memcap %u flows\n", pruned); + + return pruned; +} + unsigned FlowCache::timeout(unsigned num_flows, time_t thetime) { ActiveSuspendContext act_susp(Active::ASP_TIMEOUT); diff --git a/src/flow/flow_cache.h b/src/flow/flow_cache.h index 10d4cafec..a3eb84c6d 100644 --- a/src/flow/flow_cache.h +++ b/src/flow/flow_cache.h @@ -61,6 +61,7 @@ public: bool prune_one(PruneReason, bool do_cleanup); unsigned timeout(unsigned num_flows, time_t cur_time); unsigned delete_flows(unsigned num_to_delete); + unsigned prune_multiple(PruneReason, bool do_cleanup); unsigned purge(); unsigned get_count(); diff --git a/src/flow/flow_config.h b/src/flow/flow_config.h index b76b87d24..13dd833a9 100644 --- a/src/flow/flow_config.h +++ b/src/flow/flow_config.h @@ -34,6 +34,7 @@ struct FlowCacheConfig unsigned max_flows = 0; unsigned pruning_timeout = 0; FlowTypeConfig proto[to_utype(PktType::MAX)]; + unsigned prune_flows = 0; }; #endif diff --git a/src/flow/flow_control.cc b/src/flow/flow_control.cc index 0a6d3ebf5..ede057017 100644 --- a/src/flow/flow_control.cc +++ b/src/flow/flow_control.cc @@ -127,6 +127,9 @@ unsigned FlowControl::delete_flows(unsigned num_to_delete) bool FlowControl::prune_one(PruneReason reason, bool do_cleanup) { return cache->prune_one(reason, do_cleanup); } +unsigned FlowControl::prune_multiple(PruneReason reason, bool do_cleanup) +{ return cache->prune_multiple(reason, do_cleanup); } + void FlowControl::timeout_flows(unsigned max, time_t cur_time) { cache->timeout(max, cur_time); diff --git a/src/flow/flow_control.h b/src/flow/flow_control.h index f2b4152c8..500d9f5a8 100644 --- a/src/flow/flow_control.h +++ b/src/flow/flow_control.h @@ -70,6 +70,7 @@ public: void timeout_flows(unsigned int, time_t cur_time); void check_expected_flow(snort::Flow*, snort::Packet*); bool is_expected(snort::Packet*); + unsigned prune_multiple(PruneReason, bool do_cleanup); int add_expected_ignore( const snort::Packet* ctrlPkt, PktType, IpProtocol, diff --git a/src/flow/test/flow_control_test.cc b/src/flow/test/flow_control_test.cc index 27abccf57..8d4bcba57 100644 --- a/src/flow/test/flow_control_test.cc +++ b/src/flow/test/flow_control_test.cc @@ -79,6 +79,7 @@ Flow* FlowCache::find(const FlowKey*) { return nullptr; } Flow* FlowCache::allocate(const FlowKey*) { return nullptr; } void FlowCache::push(Flow*) { } bool FlowCache::prune_one(PruneReason, bool) { return true; } +unsigned FlowCache::prune_multiple(PruneReason , bool) { return 0; } unsigned FlowCache::delete_flows(unsigned) { return 0; } unsigned FlowCache::timeout(unsigned, time_t) { return 1; } size_t FlowCache::uni_flows_size() const { return 0; } diff --git a/src/stream/base/stream_module.cc b/src/stream/base/stream_module.cc index 6a2a508a2..ddd85b5d4 100644 --- a/src/stream/base/stream_module.cc +++ b/src/stream/base/stream_module.cc @@ -85,6 +85,9 @@ static const Parameter s_params[] = { "max_flows", Parameter::PT_INT, "2:max32", "476288", "maximum simultaneous flows tracked before pruning" }, + { "prune_flows", Parameter::PT_INT, "1:max32", "10", + "maximum flows to prune at one time" }, + { "pruning_timeout", Parameter::PT_INT, "1:max32", "30", "minimum inactive time before being eligible for pruning" }, @@ -178,6 +181,11 @@ bool StreamModule::set(const char* fqn, Value& v, SnortConfig* c) config.flow_cache_cfg.max_flows = v.get_uint32(); return true; } + else if ( v.is("prune_flows") ) + { + config.flow_cache_cfg.prune_flows = v.get_uint32(); + return true; + } else if ( v.is("pruning_timeout") ) { config.flow_cache_cfg.pruning_timeout = v.get_uint32(); @@ -343,6 +351,7 @@ void StreamModuleConfig::show() const ConfigLogger::log_value("max_flows", flow_cache_cfg.max_flows); ConfigLogger::log_value("max_aux_ip", SnortConfig::get_conf()->max_aux_ip); ConfigLogger::log_value("pruning_timeout", flow_cache_cfg.pruning_timeout); + ConfigLogger::log_value("prune_flows", flow_cache_cfg.prune_flows); for (int i = to_utype(PktType::IP); i < to_utype(PktType::PDU); ++i) { diff --git a/src/stream/stream.cc b/src/stream/stream.cc index 68116b524..9d5a828f5 100644 --- a/src/stream/stream.cc +++ b/src/stream/stream.cc @@ -388,7 +388,7 @@ bool Stream::prune_flows() if ( !flow_con ) return false; - return flow_con->prune_one(PruneReason::MEMCAP, false); + return flow_con->prune_multiple(PruneReason::MEMCAP, false); } //-------------------------------------------------------------------------