]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
next step - synchronous offload
authorRuss Combs <rucombs@cisco.com>
Tue, 25 Oct 2016 10:16:14 +0000 (06:16 -0400)
committerRuss Combs <rucombs@cisco.com>
Wed, 18 Jan 2017 15:36:19 +0000 (10:36 -0500)
src/detection/context_switcher.cc
src/detection/context_switcher.h
src/detection/detection_engine.cc
src/detection/fp_config.h
src/detection/fp_detect.cc
src/detection/ips_context.cc
src/flow/flow.h
src/main/modules.cc
src/protocols/packet.h
src/utils/stats.cc
src/utils/stats.h

index ae5a50145979be417fb6cbf435f1bba9890f9b64..da2e4fe6dd870a85dabd608f121c2e699abfee77 100644 (file)
@@ -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);
index 6d2eb24783be5bda3ff42f777b190bc247bc5337..756ce812c64000f24069af064732e293dc5743be 100644 (file)
@@ -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<IpsContext*> idle;
     std::vector<IpsContext*> busy;
index 193f160f648d0237bcf1cc7712b3cad2e738745b..dff4d2624a0c6203639ddc16f8da05a71fbcaea0 100644 (file)
@@ -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:
index 9095355503ea514bef0732a67bdcd1eba5549433..e4e85f1f093a8a65ab7114661f04ac587e1850e7 100644 (file)
@@ -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;
index 31c10e1266ba7a8ad4910bf1ec3c989c9e47938a..0d896862b269d376d030844710ba1bd7aa74cad5 100644 (file)
@@ -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"
 #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;
 }
 
index 90b169cc854fc53ed6e8a0d7a06ccf67a7671922..5f136c22a057f5d692914e386ab65fc2786d1838 100644 (file)
@@ -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);
 }
 
index b567508f09465fb74664c3a3d772faaed485abfd..6efd695d7d8ef309a3a2e14fd27d4e36e849af13 100644 (file)
@@ -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)
     {
index 98e4fc8a977e988f6b5b58a83f20030d004701d7..6795960572d152319463572429a526caf3bb7c7d 100644 (file)
@@ -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()) )
index b02d6a795d1a0fda1dfc2c0888aeafe8442c3515..41550685b47d5d6e16bd8aa66e67eed06cf4ebd4 100644 (file)
@@ -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 */
index 502e5b599fb0f1104a82a300be9e64435b381505..1ed38c2d81de869e367ff41e6b7bf966ac718700 100644 (file)
@@ -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" },
index f9e16fe5efab4907e31c44502d87d88253e73a85..232d98a841908460b53dd22fe2364d1174fbefb6 100644 (file)
@@ -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;