]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
luajit: prealloc lua states to increases chances of alloc success. Luajit requires...
authorVictor Julien <victor@inliniac.net>
Fri, 21 Sep 2012 12:18:53 +0000 (14:18 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 21 Sep 2012 12:18:53 +0000 (14:18 +0200)
src/detect-luajit.c
src/detect-luajit.h
src/detect.c
src/detect.h
src/suricata.c

index 8d405c628ae7fd5ed0310412fc7dcfb8951c1bc5..57f48a40cc3c3e2f5cebacaf1b18e4dec9065cd4 100644 (file)
@@ -23,6 +23,8 @@
  */
 
 #include "suricata-common.h"
+#include "conf.h"
+
 #include "threads.h"
 #include "debug.h"
 #include "decode.h"
@@ -76,6 +78,8 @@ void DetectLuajitRegister(void) {
 
 #else /* HAVE_LUAJIT */
 
+#include "util-pool.h"
+
 static int DetectLuajitMatch (ThreadVars *, DetectEngineThreadCtx *,
         Packet *, Signature *, SigMatch *);
 static int DetectLuajitSetup (DetectEngineCtx *, Signature *, char *);
@@ -96,6 +100,21 @@ void DetectLuajitRegister(void) {
     return;
 }
 
+/** \brief lua_State pool
+ *
+ *  Luajit requires states to be alloc'd in memory <2GB. For this reason we
+ *  prealloc the states early during engine startup so we have a better chance
+ *  of getting the states. We protect the pool with a lock as the detect
+ *  threads access it during their init and cleanup.
+ *
+ *  Pool size is automagically determined based on number of keyword occurences,
+ *  cpus/cores and rule reloads being enabled or not.
+ *
+ *  Alternatively, the "detect-engine.luajit-states" var can be set.
+ */
+static Pool *luajit_states = NULL;
+static pthread_mutex_t luajit_states_lock = PTHREAD_MUTEX_INITIALIZER;
+
 #define DATATYPE_PACKET                     (1<<0)
 #define DATATYPE_PAYLOAD                    (1<<1)
 #define DATATYPE_STREAM                     (1<<2)
@@ -114,6 +133,69 @@ void DetectLuajitRegister(void) {
 #define DATATYPE_HTTP_RESPONSE_COOKIE       (1<<11)
 #define DATATYPE_HTTP_RESPONSE_BODY         (1<<12)
 
+static void *LuaStatePoolAlloc(void) {
+    return luaL_newstate();
+}
+
+static void LuaStatePoolClean(void *d) {
+    lua_State *s = (lua_State *)d;
+    if (s != NULL)
+        lua_close(s);
+}
+
+/** \brief Populate lua states pool
+ *
+ *  \param num keyword instances
+ *  \param reloads bool indicating we have rule reloads enabled
+ */
+int DetectLuajitSetupStatesPool(int num, int reloads) {
+    int retval = 0;
+    pthread_mutex_lock(&luajit_states_lock);
+
+    if (luajit_states == NULL) {
+        int cnt = 0;
+        char *conf_val = NULL;
+
+        if ((ConfGet("detect-engine.luajit-states", &conf_val)) == 1) {
+            cnt = (int)atoi(conf_val);
+        } else {
+            int cpus = UtilCpuGetNumProcessorsOnline();
+            if (cpus == 0) {
+                cpus = 10;
+            }
+            cnt = num * cpus;
+
+            /* alloc a bunch extra so reload can add new rules/instances */
+            if (reloads)
+                cnt *= 5;
+        }
+
+        luajit_states = PoolInit(0, cnt, 0, LuaStatePoolAlloc, NULL, NULL, LuaStatePoolClean);
+        if (luajit_states == NULL) {
+            SCLogError(SC_ERR_LUAJIT_ERROR, "luastate pool init failed, luajit keywords won't work");
+            retval = -1;
+        }
+    }
+
+    pthread_mutex_unlock(&luajit_states_lock);
+    return retval;
+}
+
+static lua_State *DetectLuajitGetState(void) {
+
+    lua_State *s = NULL;
+    pthread_mutex_lock(&luajit_states_lock);
+    if (luajit_states != NULL)
+        s = (lua_State *)PoolGet(luajit_states);
+    pthread_mutex_unlock(&luajit_states_lock);
+    return s;
+}
+
+static void DetectLuajitReturnState(lua_State *s) {
+    pthread_mutex_lock(&luajit_states_lock);
+    PoolReturn(luajit_states, (void *)s);
+    pthread_mutex_unlock(&luajit_states_lock);
+}
 
 /** \brief dump stack from lua state to screen */
 void LuaDumpStack(lua_State *state) {
@@ -382,10 +464,9 @@ static void *DetectLuajitThreadInit(void *data) {
     t->alproto = luajit->alproto;
     t->flags = luajit->flags;
 
-    t->luastate = luaL_newstate();
-
+    t->luastate = DetectLuajitGetState();
     if (t->luastate == NULL) {
-        SCLogError(SC_ERR_LUAJIT_ERROR, "couldn't set up luastate");
+        SCLogError(SC_ERR_LUAJIT_ERROR, "luastate pool depleted");
         goto error;
     }
 
@@ -406,8 +487,8 @@ static void *DetectLuajitThreadInit(void *data) {
     return (void *)t;
 
 error:
-    if (t->luastate)
-        lua_close(t->luastate);
+    if (t->luastate != NULL)
+        DetectLuajitReturnState(t->luastate);
     SCFree(t);
     return NULL;
 }
@@ -415,7 +496,8 @@ error:
 static void DetectLuajitThreadFree(void *ctx) {
     if (ctx != NULL) {
         DetectLuajitThreadData *t = (DetectLuajitThreadData *)ctx;
-        lua_close(t->luastate);
+        if (t->luastate != NULL)
+            DetectLuajitReturnState(t->luastate);
         SCFree(t);
     }
 }
@@ -660,6 +742,8 @@ static int DetectLuajitSetup (DetectEngineCtx *de_ctx, Signature *s, char *str)
         else
             SigMatchAppendSMToList(s, sm, DETECT_SM_LIST_AMATCH);
     }
+
+    de_ctx->detect_luajit_instances++;
     return 0;
 
 error:
index 85dbc7ef6c3e224ab118977b7d42982ec8adf684..c96dfa58721ec55488962a3c24b1aaf09e781077 100644 (file)
@@ -50,4 +50,6 @@ typedef struct DetectLuajitData {
 void DetectLuajitRegister (void);
 int DetectLuajitMatchBuffer(DetectEngineThreadCtx *det_ctx, Signature *s, SigMatch *sm, uint8_t *buffer, uint32_t buffer_len, uint32_t offset);
 
+int DetectLuajitSetupStatesPool(int num, int reloads);
+
 #endif /* __DETECT_FILELUAJIT_H__ */
index c75f9fb9419b9b5d714681bf7c2766b72038c629..705ed7cf9b3fa268ad2f5bfc72eb4dd8657b7f79 100644 (file)
 #include "runmodes.h"
 
 extern uint8_t engine_mode;
+extern int rule_reload;
 
 extern int engine_analysis;
 static int fp_engine_analysis_set = 0;
@@ -2652,6 +2653,12 @@ int SigAddressPrepareStage1(DetectEngineCtx *de_ctx) {
                    "adding signatures to signature source addresses...");
     }
 
+    /* run this before the mpm states are initialized */
+    if (DetectLuajitSetupStatesPool(de_ctx->detect_luajit_instances, rule_reload) != 0) {
+        if (de_ctx->failure_fatal)
+            return -1;
+    }
+
     de_ctx->sig_array_len = DetectEngineGetMaxSigId(de_ctx);
     de_ctx->sig_array_size = (de_ctx->sig_array_len * sizeof(Signature *));
     de_ctx->sig_array = (Signature **)SCMalloc(de_ctx->sig_array_size);
index 88e4b4d6717657542e23f5253368cc76c12dcf0b..3292a656185cccbb68dd5de124a8c9dfa3062892 100644 (file)
@@ -690,6 +690,8 @@ typedef struct DetectEngineCtx_ {
     DetectEngineThreadKeywordCtxItem *keyword_list;
     int keyword_id;
 
+    int detect_luajit_instances;
+
 #ifdef PROFILING
     struct SCProfileDetectCtx_ *profile_ctx;
 #endif
index 3b2a82979f60cde8bdb33d47df09351e9bc74314..1a1c6b3eafd04d9020f133759df2a90298d5c0f6 100644 (file)
@@ -204,6 +204,8 @@ SC_ATOMIC_DECLARE(unsigned int, engine_stage);
 /* Max packets processed simultaniously. */
 #define DEFAULT_MAX_PENDING_PACKETS 1024
 
+int rule_reload = 0;
+
 /** suricata engine control flags */
 uint8_t suricata_ctl_flags = 0;
 
@@ -685,7 +687,6 @@ int main(int argc, char **argv)
     uint32_t groupid = 0;
 #endif /* OS_WIN32 */
     int build_info = 0;
-    int rule_reload = 0;
     int delayed_detect = 0;
 
     char *log_dir;