From 98484ffdccb3b9b0564e5dca0ceb91a5f1d9e1c8 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Fri, 21 Sep 2012 14:18:53 +0200 Subject: [PATCH] luajit: prealloc lua states to increases chances of alloc success. Luajit requires them to be in memory <2GB. --- src/detect-luajit.c | 96 ++++++++++++++++++++++++++++++++++++++++++--- src/detect-luajit.h | 2 + src/detect.c | 7 ++++ src/detect.h | 2 + src/suricata.c | 3 +- 5 files changed, 103 insertions(+), 7 deletions(-) diff --git a/src/detect-luajit.c b/src/detect-luajit.c index 8d405c628a..57f48a40cc 100644 --- a/src/detect-luajit.c +++ b/src/detect-luajit.c @@ -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: diff --git a/src/detect-luajit.h b/src/detect-luajit.h index 85dbc7ef6c..c96dfa5872 100644 --- a/src/detect-luajit.h +++ b/src/detect-luajit.h @@ -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__ */ diff --git a/src/detect.c b/src/detect.c index c75f9fb941..705ed7cf9b 100644 --- a/src/detect.c +++ b/src/detect.c @@ -189,6 +189,7 @@ #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); diff --git a/src/detect.h b/src/detect.h index 88e4b4d671..3292a65618 100644 --- a/src/detect.h +++ b/src/detect.h @@ -690,6 +690,8 @@ typedef struct DetectEngineCtx_ { DetectEngineThreadKeywordCtxItem *keyword_list; int keyword_id; + int detect_luajit_instances; + #ifdef PROFILING struct SCProfileDetectCtx_ *profile_ctx; #endif diff --git a/src/suricata.c b/src/suricata.c index 3b2a82979f..1a1c6b3eaf 100644 --- a/src/suricata.c +++ b/src/suricata.c @@ -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;