prefilter: use array of engines per sgh

Instead of the linked list of engines setup an array
with the engines. This should provide better locality.

Also shrink the engine structure so that we can fit
2 on a cacheline.

Remove the FreeFunc from the runtime engines. Engines
now have a 'gid' (global id) that can be used to look
up the registered Free function.
pull/2310/head
Victor Julien 9 years ago
parent 8321f04ef3
commit 798ba010ca

@ -55,9 +55,14 @@
#include "util-profiling.h" #include "util-profiling.h"
#ifdef PROFILING typedef struct PrefilterStore_ {
static int PrefilterStoreGetId(const char *name); const char *name;
#endif void (*FreeFunc)(void *);
uint32_t id;
} PrefilterStore;
static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *));
static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id);
static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n) static inline void QuickSortSigIntId(SigIntId *sids, uint32_t n)
{ {
@ -124,12 +129,14 @@ static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx,
goto next; goto next;
PROFILING_PREFILTER_START(p); PROFILING_PREFILTER_START(p);
engine->PrefilterTx(det_ctx, engine->pectx, engine->cb.PrefilterTx(det_ctx, engine->pectx,
p, p->flow, tx, idx, flags); p, p->flow, tx, idx, flags);
PROFILING_PREFILTER_END(p, engine->profile_id); PROFILING_PREFILTER_END(p, engine->gid);
next: next:
engine = engine->next; if (engine->is_last)
} while (engine); break;
engine++;
} while (1);
} }
} }
@ -138,7 +145,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh,
{ {
SCEnter(); SCEnter();
PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->profile_prefilter_maxid); PROFILING_PREFILTER_RESET(p, det_ctx->de_ctx->prefilter_maxid);
if (sgh->pkt_engines) { if (sgh->pkt_engines) {
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PKT);
@ -146,11 +153,13 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh,
PrefilterEngine *engine = sgh->pkt_engines; PrefilterEngine *engine = sgh->pkt_engines;
do { do {
PROFILING_PREFILTER_START(p); PROFILING_PREFILTER_START(p);
engine->Prefilter(det_ctx, p, engine->pectx); engine->cb.Prefilter(det_ctx, p, engine->pectx);
PROFILING_PREFILTER_END(p, engine->profile_id); PROFILING_PREFILTER_END(p, engine->gid);
engine = engine->next; if (engine->is_last)
} while (engine != NULL); break;
engine++;
} while (1);
PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PKT);
} }
@ -160,12 +169,14 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh,
!(p->flags & PKT_NOPAYLOAD_INSPECTION)) { !(p->flags & PKT_NOPAYLOAD_INSPECTION)) {
PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD);
PrefilterEngine *engine = sgh->payload_engines; PrefilterEngine *engine = sgh->payload_engines;
while (engine) { while (1) {
PROFILING_PREFILTER_START(p); PROFILING_PREFILTER_START(p);
engine->Prefilter(det_ctx, p, engine->pectx); engine->cb.Prefilter(det_ctx, p, engine->pectx);
PROFILING_PREFILTER_END(p, engine->profile_id); PROFILING_PREFILTER_END(p, engine->gid);
engine = engine->next; if (engine->is_last)
break;
engine++;
} }
PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD); PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD);
} }
@ -198,7 +209,7 @@ int PrefilterAppendEngine(SigGroupHead *sgh,
if (sgh == NULL || Prefilter == NULL || pectx == NULL) if (sgh == NULL || Prefilter == NULL || pectx == NULL)
return -1; return -1;
PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
if (e == NULL) if (e == NULL)
return -1; return -1;
memset(e, 0x00, sizeof(*e)); memset(e, 0x00, sizeof(*e));
@ -207,10 +218,10 @@ int PrefilterAppendEngine(SigGroupHead *sgh,
e->pectx = pectx; e->pectx = pectx;
e->Free = FreeFunc; e->Free = FreeFunc;
if (sgh->pkt_engines == NULL) { if (sgh->init->pkt_engines == NULL) {
sgh->pkt_engines = e; sgh->init->pkt_engines = e;
} else { } else {
PrefilterEngine *t = sgh->pkt_engines; PrefilterEngineList *t = sgh->init->pkt_engines;
while (t->next != NULL) { while (t->next != NULL) {
t = t->next; t = t->next;
} }
@ -219,11 +230,8 @@ int PrefilterAppendEngine(SigGroupHead *sgh,
e->id = t->id + 1; e->id = t->id + 1;
} }
#ifdef PROFILING
sgh->engines_cnt = e->id;
e->name = name; e->name = name;
e->profile_id = PrefilterStoreGetId(e->name); e->gid = PrefilterStoreGetId(e->name, e->Free);
#endif
return 0; return 0;
} }
@ -235,7 +243,7 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh,
if (sgh == NULL || Prefilter == NULL || pectx == NULL) if (sgh == NULL || Prefilter == NULL || pectx == NULL)
return -1; return -1;
PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
if (e == NULL) if (e == NULL)
return -1; return -1;
memset(e, 0x00, sizeof(*e)); memset(e, 0x00, sizeof(*e));
@ -244,10 +252,10 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh,
e->pectx = pectx; e->pectx = pectx;
e->Free = FreeFunc; e->Free = FreeFunc;
if (sgh->payload_engines == NULL) { if (sgh->init->payload_engines == NULL) {
sgh->payload_engines = e; sgh->init->payload_engines = e;
} else { } else {
PrefilterEngine *t = sgh->payload_engines; PrefilterEngineList *t = sgh->init->payload_engines;
while (t->next != NULL) { while (t->next != NULL) {
t = t->next; t = t->next;
} }
@ -256,11 +264,8 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh,
e->id = t->id + 1; e->id = t->id + 1;
} }
#ifdef PROFILING
sgh->engines_cnt = e->id;
e->name = name; e->name = name;
e->profile_id = PrefilterStoreGetId(e->name); e->gid = PrefilterStoreGetId(e->name, e->Free);
#endif
return 0; return 0;
} }
@ -275,7 +280,7 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh,
if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) if (sgh == NULL || PrefilterTx == NULL || pectx == NULL)
return -1; return -1;
PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS);
if (e == NULL) if (e == NULL)
return -1; return -1;
memset(e, 0x00, sizeof(*e)); memset(e, 0x00, sizeof(*e));
@ -286,10 +291,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh,
e->tx_min_progress = tx_min_progress; e->tx_min_progress = tx_min_progress;
e->Free = FreeFunc; e->Free = FreeFunc;
if (sgh->tx_engines == NULL) { if (sgh->init->tx_engines == NULL) {
sgh->tx_engines = e; sgh->init->tx_engines = e;
} else { } else {
PrefilterEngine *t = sgh->tx_engines; PrefilterEngineList *t = sgh->init->tx_engines;
while (t->next != NULL) { while (t->next != NULL) {
t = t->next; t = t->next;
} }
@ -297,33 +302,64 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh,
t->next = e; t->next = e;
e->id = t->id + 1; e->id = t->id + 1;
} }
#ifdef PROFILING
sgh->tx_engines_cnt = e->id;
e->name = name; e->name = name;
e->profile_id = PrefilterStoreGetId(e->name); e->gid = PrefilterStoreGetId(e->name, e->Free);
#endif
return 0; return 0;
} }
static void PrefilterFreeEngine(PrefilterEngine *e) static void PrefilterFreeEngineList(PrefilterEngineList *e)
{ {
if (e->Free) { if (e->Free && e->pectx) {
e->Free(e->pectx); e->Free(e->pectx);
} }
SCFreeAligned(e); SCFreeAligned(e);
} }
void PrefilterFreeEngines(PrefilterEngine *list) void PrefilterFreeEnginesList(PrefilterEngineList *list)
{ {
PrefilterEngine *t = list; PrefilterEngineList *t = list;
while (t != NULL) { while (t != NULL) {
PrefilterEngine *next = t->next; PrefilterEngineList *next = t->next;
PrefilterFreeEngine(t); PrefilterFreeEngineList(t);
t = next; t = next;
} }
} }
static void PrefilterFreeEngines(PrefilterEngine *list)
{
PrefilterEngine *t = list;
while (1) {
const PrefilterStore *s = PrefilterStoreGetStore(t->gid);
if (s && s->FreeFunc && t->pectx) {
s->FreeFunc(t->pectx);
}
if (t->is_last)
break;
t++;
}
SCFreeAligned(list);
}
void PrefilterCleanupRuleGroup(SigGroupHead *sgh)
{
if (sgh->pkt_engines) {
PrefilterFreeEngines(sgh->pkt_engines);
sgh->pkt_engines = NULL;
}
if (sgh->payload_engines) {
PrefilterFreeEngines(sgh->payload_engines);
sgh->payload_engines = NULL;
}
if (sgh->tx_engines) {
PrefilterFreeEngines(sgh->tx_engines);
sgh->tx_engines = NULL;
}
}
void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
{ {
BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0);
@ -338,35 +374,90 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh)
} }
} }
#ifdef PROFILING /* we have lists of engines in sgh->init now. Lets setup the
PrefilterEngine *e; * match arrays */
uint32_t engines = 0; PrefilterEngineList *el;
uint32_t tx_engines = 0; if (sgh->init->pkt_engines != NULL) {
uint32_t cnt = 0;
for (e = sgh->pkt_engines ; e != NULL; e = e->next) { for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
engines++; cnt++;
de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
}
sgh->pkt_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
if (sgh->pkt_engines == NULL) {
return;
}
memset(sgh->pkt_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
PrefilterEngine *e = sgh->pkt_engines;
for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) {
e->id = el->id;
e->cb.Prefilter = el->Prefilter;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
e->gid = el->gid;
if (el->next == NULL) {
e->is_last = TRUE;
}
e++;
}
} }
for (e = sgh->payload_engines ; e != NULL; e = e->next) { if (sgh->init->payload_engines != NULL) {
engines++; uint32_t cnt = 0;
de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
cnt++;
de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
}
sgh->payload_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
if (sgh->payload_engines == NULL) {
return;
}
memset(sgh->payload_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
PrefilterEngine *e = sgh->payload_engines;
for (el = sgh->init->payload_engines ; el != NULL; el = el->next) {
e->id = el->id;
e->cb.Prefilter = el->Prefilter;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
e->gid = el->gid;
if (el->next == NULL) {
e->is_last = TRUE;
}
e++;
}
} }
for (e = sgh->tx_engines ; e != NULL; e = e->next) { if (sgh->init->tx_engines != NULL) {
tx_engines++; uint32_t cnt = 0;
de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
cnt++;
de_ctx->prefilter_maxid = MAX(de_ctx->prefilter_maxid, el->gid);
}
sgh->tx_engines = SCMallocAligned(cnt * sizeof(PrefilterEngine), CLS);
if (sgh->tx_engines == NULL) {
return;
}
memset(sgh->tx_engines, 0x00, (cnt * sizeof(PrefilterEngine)));
PrefilterEngine *e = sgh->tx_engines;
for (el = sgh->init->tx_engines ; el != NULL; el = el->next) {
e->id = el->id;
e->alproto = el->alproto;
e->tx_min_progress = el->tx_min_progress;
e->cb.PrefilterTx = el->PrefilterTx;
e->pectx = el->pectx;
el->pectx = NULL; // e now owns the ctx
e->gid = el->gid;
if (el->next == NULL) {
e->is_last = TRUE;
}
e++;
}
} }
SCLogDebug("SGH %p: engines %u tx_engines %u", sgh, engines, tx_engines);
#endif
} }
#ifdef PROFILING
/* hash table for assigning a unique id to each engine type. */ /* hash table for assigning a unique id to each engine type. */
typedef struct PrefilterStore_ {
const char *name;
uint32_t id;
} PrefilterStore;
static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen)
{ {
PrefilterStore *ctx = data; PrefilterStore *ctx = data;
@ -421,9 +512,9 @@ static void PrefilterInit(void)
SCMutexUnlock(&g_prefilter_mutex); SCMutexUnlock(&g_prefilter_mutex);
} }
static int PrefilterStoreGetId(const char *name) static int PrefilterStoreGetId(const char *name, void (*FreeFunc)(void *))
{ {
PrefilterStore ctx = { name, 0 }; PrefilterStore ctx = { name, FreeFunc, 0 };
if (g_prefilter_hash_table == NULL) { if (g_prefilter_hash_table == NULL) {
PrefilterInit(); PrefilterInit();
@ -445,6 +536,7 @@ static int PrefilterStoreGetId(const char *name)
} }
actx->name = name; actx->name = name;
actx->FreeFunc = FreeFunc;
actx->id = g_prefilter_id++; actx->id = g_prefilter_id++;
SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id); SCLogDebug("prefilter engine %s has profile id %u", actx->name, actx->id);
@ -460,6 +552,25 @@ static int PrefilterStoreGetId(const char *name)
return r; return r;
} }
/** \warning slow */
static const PrefilterStore *PrefilterStoreGetStore(const uint32_t id)
{
const PrefilterStore *store = NULL;
SCMutexLock(&g_prefilter_mutex);
if (g_prefilter_hash_table != NULL) {
HashListTableBucket *hb = HashListTableGetListHead(g_prefilter_hash_table);
for ( ; hb != NULL; hb = HashListTableGetListNext(hb)) {
PrefilterStore *ctx = HashListTableGetListData(hb);
if (ctx->id == id) {
store = ctx;
break;
}
}
}
SCMutexUnlock(&g_prefilter_mutex);
return store;
}
/** \warning slow */ /** \warning slow */
const char *PrefilterStoreGetName(const uint32_t id) const char *PrefilterStoreGetName(const uint32_t id)
{ {
@ -478,4 +589,3 @@ const char *PrefilterStoreGetName(const uint32_t id)
SCMutexUnlock(&g_prefilter_mutex); SCMutexUnlock(&g_prefilter_mutex);
return name; return name;
} }
#endif /* PROFILING */

@ -43,9 +43,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh,
void *pectx, void (*FreeFunc)(void *pectx), void *pectx, void (*FreeFunc)(void *pectx),
const char *name); const char *name);
void PrefilterFreeEngines(PrefilterEngine *list); void PrefilterFreeEnginesList(PrefilterEngineList *list);
void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh); void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh);
void PrefilterCleanupRuleGroup(SigGroupHead *sgh);
#ifdef PROFILING #ifdef PROFILING
const char *PrefilterStoreGetName(const uint32_t id); const char *PrefilterStoreGetName(const uint32_t id);

@ -64,6 +64,11 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid)
if (sghid->app_mpms != NULL) { if (sghid->app_mpms != NULL) {
SCFree(sghid->app_mpms); SCFree(sghid->app_mpms);
} }
PrefilterFreeEnginesList(sghid->tx_engines);
PrefilterFreeEnginesList(sghid->pkt_engines);
PrefilterFreeEnginesList(sghid->payload_engines);
SCFree(sghid); SCFree(sghid);
} }
@ -174,10 +179,7 @@ void SigGroupHeadFree(SigGroupHead *sgh)
sgh->init = NULL; sgh->init = NULL;
} }
PrefilterFreeEngines(sgh->tx_engines); PrefilterCleanupRuleGroup(sgh);
PrefilterFreeEngines(sgh->pkt_engines);
PrefilterFreeEngines(sgh->payload_engines);
SCFree(sgh); SCFree(sgh);
return; return;

@ -723,8 +723,8 @@ typedef struct DetectEngineCtx_ {
struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX];
struct SCProfileSghDetectCtx_ *profile_sgh_ctx; struct SCProfileSghDetectCtx_ *profile_sgh_ctx;
uint32_t profile_match_logging_threshold; uint32_t profile_match_logging_threshold;
uint32_t profile_prefilter_maxid;
#endif #endif
uint32_t prefilter_maxid;
char config_prefix[64]; char config_prefix[64];
@ -1019,7 +1019,7 @@ typedef struct MpmStore_ {
} MpmStore; } MpmStore;
typedef struct PrefilterEngine_ { typedef struct PrefilterEngineList_ {
uint16_t id; uint16_t id;
/** App Proto this engine applies to: only used with Tx Engines */ /** App Proto this engine applies to: only used with Tx Engines */
@ -1037,15 +1037,39 @@ typedef struct PrefilterEngine_ {
Packet *p, Flow *f, void *tx, Packet *p, Flow *f, void *tx,
const uint64_t idx, const uint8_t flags); const uint64_t idx, const uint8_t flags);
struct PrefilterEngine_ *next; struct PrefilterEngineList_ *next;
/** Free function for pectx data. If NULL the memory is not freed. */ /** Free function for pectx data. If NULL the memory is not freed. */
void (*Free)(void *pectx); void (*Free)(void *pectx);
const char *name; const char *name;
#ifdef PROFILING /* global id for this prefilter */
uint32_t profile_id; uint32_t gid;
#endif } PrefilterEngineList;
typedef struct PrefilterEngine_ {
uint16_t id;
/** App Proto this engine applies to: only used with Tx Engines */
AppProto alproto;
/** Minimal Tx progress we need before running the engine. Only used
* with Tx Engine */
int tx_min_progress;
/** Context for matching. Might be MpmCtx for MPM engines, other ctx'
* for other engines. */
void *pectx;
union {
void (*Prefilter)(DetectEngineThreadCtx *det_ctx, Packet *p, const void *pectx);
void (*PrefilterTx)(DetectEngineThreadCtx *det_ctx, const void *pectx,
Packet *p, Flow *f, void *tx,
const uint64_t idx, const uint8_t flags);
} cb;
/* global id for this prefilter */
uint32_t gid;
int is_last;
} PrefilterEngine; } PrefilterEngine;
typedef struct SigGroupHeadInitData_ { typedef struct SigGroupHeadInitData_ {
@ -1060,6 +1084,10 @@ typedef struct SigGroupHeadInitData_ {
MpmCtx **app_mpms; MpmCtx **app_mpms;
PrefilterEngineList *pkt_engines;
PrefilterEngineList *payload_engines;
PrefilterEngineList *tx_engines;
/* port ptr */ /* port ptr */
struct DetectPort_ *port; struct DetectPort_ *port;
} SigGroupHeadInitData; } SigGroupHeadInitData;
@ -1087,11 +1115,6 @@ typedef struct SigGroupHead_ {
PrefilterEngine *payload_engines; PrefilterEngine *payload_engines;
PrefilterEngine *tx_engines; PrefilterEngine *tx_engines;
#ifdef PROFILING
uint32_t engines_cnt;
uint32_t tx_engines_cnt;
#endif
/** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */ /** Array with sig ptrs... size is sig_cnt * sizeof(Signature *) */
Signature **match_array; Signature **match_array;

Loading…
Cancel
Save