From: Russ Combs Date: Tue, 25 Oct 2016 10:16:14 +0000 (-0400) Subject: next step - synchronous offload X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a82f0364aab36b03a5b48834d27f9f755f7ff3f3;p=thirdparty%2Fsnort3.git next step - synchronous offload --- diff --git a/src/detection/context_switcher.cc b/src/detection/context_switcher.cc index ae5a50145..da2e4fe6d 100644 --- a/src/detection/context_switcher.cc +++ b/src/detection/context_switcher.cc @@ -137,6 +137,14 @@ IpsContext* ContextSwitcher::get_context() const return busy.back(); } +IpsContext* ContextSwitcher::get_context(unsigned slot) const +{ + assert(slot <= hold.capacity()); + IpsContext* c = hold[slot]; + assert(c); + return c; +} + IpsContextData* ContextSwitcher::get_context_data(unsigned id) const { return get_context()->get_context_data(id); diff --git a/src/detection/context_switcher.h b/src/detection/context_switcher.h index 6d2eb2478..756ce812c 100644 --- a/src/detection/context_switcher.h +++ b/src/detection/context_switcher.h @@ -66,6 +66,8 @@ public: void resume(unsigned suspended); IpsContext* get_context() const; + IpsContext* get_context(unsigned) const; + IpsContextData* get_context_data(unsigned id) const; void set_context_data(unsigned id, IpsContextData*) const; @@ -73,6 +75,9 @@ public: unsigned busy_count() const; unsigned hold_count() const; + bool can_hold() const + { return idle_count() > 5; } // FIXIT-H define appropriate const + private: std::vector idle; std::vector busy; diff --git a/src/detection/detection_engine.cc b/src/detection/detection_engine.cc index 193f160f6..dff4d2624 100644 --- a/src/detection/detection_engine.cc +++ b/src/detection/detection_engine.cc @@ -175,6 +175,9 @@ bool DetectionEngine::detect(Packet* p) if ( p->packet_flags & PKT_PASS_RULE ) return false; + if ( PacketLatency::fastpath() ) + return false; + // FIXIT-M restrict detect to current ip layer // Curently, if a rule is found on any IP layer, we perform the detect routine // on the entire packet. Instead, we should only perform detect on that layer!! @@ -186,9 +189,6 @@ bool DetectionEngine::detect(Packet* p) case PktType::ICMP: case PktType::PDU: case PktType::FILE: - if ( PacketLatency::fastpath() ) - return false; - return fpEvalPacket(p); default: diff --git a/src/detection/fp_config.h b/src/detection/fp_config.h index 909535550..e4e85f1f0 100644 --- a/src/detection/fp_config.h +++ b/src/detection/fp_config.h @@ -52,18 +52,27 @@ public: bool get_stream_insert() { return inspect_stream_insert; } - void set_max_queue_events(unsigned int num_events) + void set_max_queue_events(unsigned num_events) { max_queue_events = num_events; } unsigned get_max_queue_events() { return max_queue_events; } - int get_single_rule_group() - { return portlists_flags & PL_SINGLE_RULE_GROUP; } + void set_bleed_over_port_limit(unsigned n) + { bleedover_port_limit = n; } int get_bleed_over_port_limit() { return bleedover_port_limit; } + void set_offload_limit(unsigned n) + { offload_limit = n; } + + unsigned get_offload_limit() + { return offload_limit; } + + int get_single_rule_group() + { return portlists_flags & PL_SINGLE_RULE_GROUP; } + int get_bleed_over_warnings() { return portlists_flags & PL_BLEEDOVER_WARNINGS_ENABLED; } @@ -94,9 +103,6 @@ public: void set_single_rule_group() { portlists_flags |= PL_SINGLE_RULE_GROUP; } - void set_bleed_over_port_limit(unsigned int n) - { bleedover_port_limit = n; } - void set_bleed_over_warnings() { portlists_flags |= PL_BLEEDOVER_WARNINGS_ENABLED; } @@ -152,6 +158,7 @@ private: unsigned max_queue_events; unsigned bleedover_port_limit; + unsigned offload_limit; int search_opt; int portlists_flags; diff --git a/src/detection/fp_detect.cc b/src/detection/fp_detect.cc index 31c10e126..0d896862b 100644 --- a/src/detection/fp_detect.cc +++ b/src/detection/fp_detect.cc @@ -31,7 +31,6 @@ ** 2005-02-17 - Track alerts per IP frag tracker so that they aren't double ** reported for rebuilt frags. SAS (code similar to AJM's for ** per session tracking). -** */ #ifdef HAVE_CONFIG_H @@ -50,6 +49,7 @@ #include "latency/packet_latency.h" #include "latency/rule_latency.h" #include "log/messages.h" +#include "main/snort.h" #include "main/snort_config.h" #include "main/snort_debug.h" #include "managers/action_manager.h" @@ -72,6 +72,20 @@ #include "pcrm.h" #include "service_map.h" +#include "context_switcher.h" +#include "detection_util.h" +#include "detection_engine.h" +#include "detection_options.h" +#include "fp_config.h" +#include "fp_create.h" +#include "ips_context.h" +#include "pattern_match_data.h" +#include "pcrm.h" +#include "rules.h" +#include "service_map.h" +#include "tag.h" +#include "treenodes.h" + THREAD_LOCAL ProfileStats rulePerfStats; THREAD_LOCAL ProfileStats ruleRTNEvalPerfStats; THREAD_LOCAL ProfileStats ruleOTNEvalPerfStats; @@ -370,7 +384,7 @@ static int rule_tree_match( last_check->ts.tv_sec = eval_data.p->pkth->ts.tv_sec; last_check->ts.tv_usec = eval_data.p->pkth->ts.tv_usec; - last_check->packet_number = DetectionEngine::get_context()->pkt_count + last_check->packet_number = eval_data.p->context->pkt_count + PacketManager::get_rebuilt_packet_count(); last_check->rebuild_flag = (eval_data.p->packet_flags & PKT_REBUILT_STREAM); } @@ -666,10 +680,7 @@ static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p) return 1; } - /* - ** Loop here so we don't log the same event - ** multiple times. - */ + // Loop here so we don't log the same event multiple times. for (k = 0; k < j; k++) { if (o->matchInfo[i].MatchArray[k] == otn) @@ -681,9 +692,6 @@ static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p) if ( otn && !fpSessionAlerted(p, otn) ) { - /* - ** QueueEvent - */ if ( DetectionEngine::queue_event(otn) ) pc.queue_limit++; @@ -721,15 +729,27 @@ static inline int fpFinalSelectEvent(OtnxMatchData* o, Packet* p) class MpseStash { public: + // FIXIT-H use max = n * k, at most k per group + // need n >= 4 for src+dst+gen+svc static const unsigned max = 32; void init() - { count = flushed = 0; } + { if ( enable ) { count = flushed = 0; } } + // this is done in the offload thread bool push(void* user, void* tree, int index, void* list); + + // this is done in the packet thread bool process(MpseMatch, void*); + void disable_process() + { enable = false; } + + void enable_process() + { enable = true; } + private: + bool enable; unsigned count; unsigned flushed; @@ -774,6 +794,9 @@ bool MpseStash::push(void* user, void* tree, int index, void* list) bool MpseStash::process(MpseMatch match, void* context) { + if ( !enable ) + return true; // maxed out - quit + if ( count > pmqs.max_inq ) pmqs.max_inq = count; @@ -821,14 +844,13 @@ void fp_clear_context(IpsContext& c) static int rule_tree_queue( void* user, void* tree, int index, void* context, void* list) { - MpseStash* stash = DetectionEngine::get_stash(); + OtnxMatchData* pomd = (OtnxMatchData*)context; + MpseStash* stash = pomd->p->context->stash; if ( stash->push(user, tree, index, list) ) { if ( stash->process(rule_tree_match, context) ) - { return 1; - } } return 0; } @@ -839,7 +861,7 @@ static int rule_tree_queue( int start_state = 0; \ cnt++; \ omd->data = buf; omd->size = len; \ - MpseStash* stash = DetectionEngine::get_stash(); \ + MpseStash* stash = omd->p->context->stash; \ stash->init(); \ so->search(buf, len, rule_tree_queue, omd, &start_state); \ stash->process(rule_tree_match, omd); \ @@ -855,8 +877,7 @@ static int rule_tree_queue( } static int fp_search( - PortGroup* port_group, Packet* p, - int check_ports, int type, OtnxMatchData* omd) + PortGroup* port_group, Packet* p, int check_ports, int type, OtnxMatchData* omd) { Inspector* gadget = p->flow ? p->flow->gadget : nullptr; InspectionBuffer buf; @@ -905,8 +926,8 @@ static int fp_search( { // FIXIT-M file data should be obtained from // inspector gadget as is done with SEARCH_BUFFER - DataPointer file_data; - DetectionEngine::get_file_data(file_data); + DataPointer file_data = p->context->file_data; + if ( file_data.len ) SEARCH_DATA(file_data.data, file_data.len, pc.file_searches); } @@ -914,6 +935,50 @@ static int fp_search( return 0; } +static int fp_tsearch( + PortGroup* port_group, Packet* p, int check_ports, int type, OtnxMatchData* omd, + SnortConfig* sc) +{ + snort_conf = sc; + return fp_search(port_group, p, check_ports, type, omd); +} + +static int fp_offload( + PortGroup* port_group, Packet* p, int check_ports, int type, OtnxMatchData* omd) +{ + MpseStash* stash = p->context->stash; + ContextSwitcher* sw = Snort::get_switcher(); + FastPatternConfig* fp = snort_conf->fast_pattern_config; + + if ( p->type() != PktType::PDU or (p->dsize < fp->get_offload_limit()) or + p->flow->test_session_flags(SSNFLAG_OFFLOAD) or !sw->can_hold() ) + { + stash->enable_process(); + return fp_search(port_group, p, check_ports, type, omd); + } + + assert(p == p->context->packet); + stash->init(); + stash->disable_process(); + + p->flow->set_session_flags(SSNFLAG_OFFLOAD); + pc.offloads++; + + unsigned id = sw->suspend(); + + std::thread t(fp_tsearch, port_group, p, check_ports, type, omd, snort_conf); + t.join(); + + sw->resume(id); + + p->flow->clear_session_flags(SSNFLAG_OFFLOAD); + stash->enable_process(); + stash->process(rule_tree_match, omd); + fpFinalSelectEvent(omd, p); + + return 0; +} + /* ** DESCRIPTION ** This function does a set-wise match on content, and walks an otn list @@ -960,7 +1025,7 @@ static inline int fpEvalHeaderSW(PortGroup* port_group, Packet* p, if ( DetectionEngine::content_enabled() ) { if ( fp->get_stream_insert() || !(p->packet_flags & PKT_STREAM_INSERT) ) - if ( fp_search(port_group, p, check_ports, type, omd) ) + if ( fp_offload(port_group, p, check_ports, type, omd) ) return 0; } @@ -1148,7 +1213,7 @@ static inline bool fpEvalHeaderSvc(Packet* p, OtnxMatchData* omd, int proto) static void fpEvalPacketUdp(Packet* p) { - OtnxMatchData* omd = DetectionEngine::get_context()->otnx; + OtnxMatchData* omd = p->context->otnx; uint16_t tmp_sp = p->ptrs.sp; uint16_t tmp_dp = p->ptrs.dp; @@ -1207,7 +1272,7 @@ static void fpEvalPacketUdp(Packet* p) */ int fpEvalPacket(Packet* p) { - OtnxMatchData* omd = DetectionEngine::get_context()->otnx; + OtnxMatchData* omd = p->context->otnx; init_match_info(omd); /* Run UDP rules against the UDP header of Teredo packets */ @@ -1261,7 +1326,9 @@ int fpEvalPacket(Packet* p) default: break; } + if ( !p->flow or !p->flow->test_session_flags(SSNFLAG_OFFLOAD) ) + return fpFinalSelectEvent(omd, p); - return fpFinalSelectEvent(omd, p); + return 0; } diff --git a/src/detection/ips_context.cc b/src/detection/ips_context.cc index 90b169cc8..5f136c22a 100644 --- a/src/detection/ips_context.cc +++ b/src/detection/ips_context.cc @@ -65,6 +65,7 @@ IpsContext::IpsContext(unsigned size) : const EventQueueConfig* qc = snort_conf->event_queue_config; equeue = sfeventq_new(qc->max_events, qc->log_events, sizeof(EventNode)); + packet->context = this; fp_set_context(*this); } diff --git a/src/flow/flow.h b/src/flow/flow.h index b567508f0..6efd695d7 100644 --- a/src/flow/flow.h +++ b/src/flow/flow.h @@ -62,6 +62,7 @@ #define SSNFLAG_CLIENT_SWAPPED 0x00400000 #define SSNFLAG_PROXIED 0x01000000 +#define SSNFLAG_OFFLOAD 0x02000000 #define SSNFLAG_NONE 0x00000000 /* nothing, an MT bag of chips */ #define SSNFLAG_SEEN_BOTH (SSNFLAG_SEEN_SERVER | SSNFLAG_SEEN_CLIENT) @@ -177,29 +178,22 @@ public: Layer get_mpls_layer_per_dir(bool); uint32_t update_session_flags(uint32_t flags) - { - return ssn_state.session_flags = flags; - } + { return ssn_state.session_flags = flags; } uint32_t set_session_flags(uint32_t flags) - { - return ssn_state.session_flags |= flags; - } - - uint32_t clear_session_flags(uint32_t flags) - { - return ssn_state.session_flags &= ~flags; - } + { return ssn_state.session_flags |= flags; } uint32_t get_session_flags() - { - return ssn_state.session_flags; - } + { return ssn_state.session_flags; } + + uint32_t test_session_flags(uint32_t flags) + { return (ssn_state.session_flags & flags) != 0; } + + uint32_t clear_session_flags(uint32_t flags) + { return ssn_state.session_flags &= ~flags; } int get_ignore_direction() - { - return ssn_state.ignore_direction; - } + { return ssn_state.ignore_direction; } int set_ignore_direction(char ignore_direction) { diff --git a/src/main/modules.cc b/src/main/modules.cc index 98e4fc8a9..679596057 100644 --- a/src/main/modules.cc +++ b/src/main/modules.cc @@ -221,6 +221,9 @@ static const Parameter search_engine_params[] = { "inspect_stream_inserts", Parameter::PT_BOOL, nullptr, "false", "inspect reassembled payload - disabling is good for performance, bad for detection" }, + { "offload_limit", Parameter::PT_INT, nullptr, "99999", + "minimum sizeof PDU to offload fast pattern search (defaults to disabled)" }, + { "search_method", Parameter::PT_DYNAMIC, (void*)&get_search_methods, "ac_bnfa", "set fast pattern algorithm - choose available search engine" }, @@ -316,6 +319,9 @@ bool SearchEngineModule::set(const char*, Value& v, SnortConfig* sc) else if ( v.is("inspect_stream_inserts") ) fp->set_stream_insert(v.get_bool()); + else if ( v.is("offload_limit") ) + fp->set_offload_limit(v.get_long()); + else if ( v.is("search_method") ) { if ( !fp->set_detect_search_method(v.get_string()) ) diff --git a/src/protocols/packet.h b/src/protocols/packet.h index b02d6a795..41550685b 100644 --- a/src/protocols/packet.h +++ b/src/protocols/packet.h @@ -120,8 +120,9 @@ struct SO_PUBLIC Packet // nothing after this point is zeroed ... // Everything beyond this point is set by PacketManager::decode() + class IpsContext* context; // set by control const DAQ_PktHdr_t* pkth; // packet meta data - const uint8_t* pkt; // raw packet data + const uint8_t* pkt; // raw packet data // These are both set before PacketManager::decode() returns const uint8_t* data; /* packet payload pointer */ diff --git a/src/utils/stats.cc b/src/utils/stats.cc index 502e5b599..1ed38c2d8 100644 --- a/src/utils/stats.cc +++ b/src/utils/stats.cc @@ -198,6 +198,7 @@ const PegInfo pc_names[] = { "header searches", "fast pattern searches in header buffer" }, { "body searches", "fast pattern searches in body buffer" }, { "file searches", "fast pattern searches in file buffer" }, + { "offloads", "fast pattern searches that were offloaded" }, { "alerts", "alerts not including IP reputation" }, { "total alerts", "alerts including IP reputation" }, { "logged", "logged packets" }, diff --git a/src/utils/stats.h b/src/utils/stats.h index f9e16fe5e..232d98a84 100644 --- a/src/utils/stats.h +++ b/src/utils/stats.h @@ -43,6 +43,7 @@ struct PacketCount PegCount header_searches; PegCount body_searches; PegCount file_searches; + PegCount offloads; PegCount alert_pkts; PegCount total_alert_pkts; PegCount log_pkts;