From 798ba010ca956310fd17f2b6ecda3c6f383c3818 Mon Sep 17 00:00:00 2001 From: Victor Julien Date: Tue, 27 Sep 2016 13:46:08 +0200 Subject: [PATCH] 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. --- src/detect-engine-prefilter.c | 252 ++++++++++++++++++++++++---------- src/detect-engine-prefilter.h | 3 +- src/detect-engine-siggroup.c | 10 +- src/detect.h | 45 ++++-- 4 files changed, 223 insertions(+), 87 deletions(-) diff --git a/src/detect-engine-prefilter.c b/src/detect-engine-prefilter.c index dee4c316dc..0b18288030 100644 --- a/src/detect-engine-prefilter.c +++ b/src/detect-engine-prefilter.c @@ -55,9 +55,14 @@ #include "util-profiling.h" -#ifdef PROFILING -static int PrefilterStoreGetId(const char *name); -#endif +typedef struct PrefilterStore_ { + const char *name; + 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) { @@ -124,12 +129,14 @@ static inline void PrefilterTx(DetectEngineThreadCtx *det_ctx, goto next; PROFILING_PREFILTER_START(p); - engine->PrefilterTx(det_ctx, engine->pectx, + engine->cb.PrefilterTx(det_ctx, engine->pectx, p, p->flow, tx, idx, flags); - PROFILING_PREFILTER_END(p, engine->profile_id); + PROFILING_PREFILTER_END(p, engine->gid); next: - engine = engine->next; - } while (engine); + if (engine->is_last) + break; + engine++; + } while (1); } } @@ -138,7 +145,7 @@ void Prefilter(DetectEngineThreadCtx *det_ctx, const SigGroupHead *sgh, { 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) { 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; do { PROFILING_PREFILTER_START(p); - engine->Prefilter(det_ctx, p, engine->pectx); - PROFILING_PREFILTER_END(p, engine->profile_id); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); - engine = engine->next; - } while (engine != NULL); + if (engine->is_last) + break; + engine++; + } while (1); 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)) { PACKET_PROFILING_DETECT_START(p, PROF_DETECT_PF_PAYLOAD); PrefilterEngine *engine = sgh->payload_engines; - while (engine) { + while (1) { PROFILING_PREFILTER_START(p); - engine->Prefilter(det_ctx, p, engine->pectx); - PROFILING_PREFILTER_END(p, engine->profile_id); + engine->cb.Prefilter(det_ctx, p, engine->pectx); + PROFILING_PREFILTER_END(p, engine->gid); - engine = engine->next; + if (engine->is_last) + break; + engine++; } PACKET_PROFILING_DETECT_END(p, PROF_DETECT_PF_PAYLOAD); } @@ -198,7 +209,7 @@ int PrefilterAppendEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -207,10 +218,10 @@ int PrefilterAppendEngine(SigGroupHead *sgh, e->pectx = pectx; e->Free = FreeFunc; - if (sgh->pkt_engines == NULL) { - sgh->pkt_engines = e; + if (sgh->init->pkt_engines == NULL) { + sgh->init->pkt_engines = e; } else { - PrefilterEngine *t = sgh->pkt_engines; + PrefilterEngineList *t = sgh->init->pkt_engines; while (t->next != NULL) { t = t->next; } @@ -219,11 +230,8 @@ int PrefilterAppendEngine(SigGroupHead *sgh, e->id = t->id + 1; } -#ifdef PROFILING - sgh->engines_cnt = e->id; e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } @@ -235,7 +243,7 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, if (sgh == NULL || Prefilter == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -244,10 +252,10 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, e->pectx = pectx; e->Free = FreeFunc; - if (sgh->payload_engines == NULL) { - sgh->payload_engines = e; + if (sgh->init->payload_engines == NULL) { + sgh->init->payload_engines = e; } else { - PrefilterEngine *t = sgh->payload_engines; + PrefilterEngineList *t = sgh->init->payload_engines; while (t->next != NULL) { t = t->next; } @@ -256,11 +264,8 @@ int PrefilterAppendPayloadEngine(SigGroupHead *sgh, e->id = t->id + 1; } -#ifdef PROFILING - sgh->engines_cnt = e->id; e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } @@ -275,7 +280,7 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, if (sgh == NULL || PrefilterTx == NULL || pectx == NULL) return -1; - PrefilterEngine *e = SCMallocAligned(sizeof(*e), CLS); + PrefilterEngineList *e = SCMallocAligned(sizeof(*e), CLS); if (e == NULL) return -1; memset(e, 0x00, sizeof(*e)); @@ -286,10 +291,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, e->tx_min_progress = tx_min_progress; e->Free = FreeFunc; - if (sgh->tx_engines == NULL) { - sgh->tx_engines = e; + if (sgh->init->tx_engines == NULL) { + sgh->init->tx_engines = e; } else { - PrefilterEngine *t = sgh->tx_engines; + PrefilterEngineList *t = sgh->init->tx_engines; while (t->next != NULL) { t = t->next; } @@ -297,33 +302,64 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, t->next = e; e->id = t->id + 1; } -#ifdef PROFILING - sgh->tx_engines_cnt = e->id; + e->name = name; - e->profile_id = PrefilterStoreGetId(e->name); -#endif + e->gid = PrefilterStoreGetId(e->name, e->Free); return 0; } -static void PrefilterFreeEngine(PrefilterEngine *e) +static void PrefilterFreeEngineList(PrefilterEngineList *e) { - if (e->Free) { + if (e->Free && e->pectx) { e->Free(e->pectx); } SCFreeAligned(e); } -void PrefilterFreeEngines(PrefilterEngine *list) +void PrefilterFreeEnginesList(PrefilterEngineList *list) { - PrefilterEngine *t = list; + PrefilterEngineList *t = list; while (t != NULL) { - PrefilterEngine *next = t->next; - PrefilterFreeEngine(t); + PrefilterEngineList *next = t->next; + PrefilterFreeEngineList(t); 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) { BUG_ON(PatternMatchPrepareGroup(de_ctx, sgh) != 0); @@ -338,35 +374,90 @@ void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh) } } -#ifdef PROFILING - PrefilterEngine *e; - uint32_t engines = 0; - uint32_t tx_engines = 0; - - for (e = sgh->pkt_engines ; e != NULL; e = e->next) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + /* we have lists of engines in sgh->init now. Lets setup the + * match arrays */ + PrefilterEngineList *el; + if (sgh->init->pkt_engines != NULL) { + uint32_t cnt = 0; + for (el = sgh->init->pkt_engines ; el != NULL; el = el->next) { + cnt++; + 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) { - engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + if (sgh->init->payload_engines != NULL) { + uint32_t cnt = 0; + 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) { - tx_engines++; - de_ctx->profile_prefilter_maxid = MAX(de_ctx->profile_prefilter_maxid, e->profile_id); + if (sgh->init->tx_engines != NULL) { + uint32_t cnt = 0; + 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. */ -typedef struct PrefilterStore_ { - const char *name; - uint32_t id; -} PrefilterStore; - static uint32_t PrefilterStoreHashFunc(HashListTable *ht, void *data, uint16_t datalen) { PrefilterStore *ctx = data; @@ -421,9 +512,9 @@ static void PrefilterInit(void) 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) { PrefilterInit(); @@ -445,6 +536,7 @@ static int PrefilterStoreGetId(const char *name) } actx->name = name; + actx->FreeFunc = FreeFunc; actx->id = g_prefilter_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; } +/** \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 */ const char *PrefilterStoreGetName(const uint32_t id) { @@ -478,4 +589,3 @@ const char *PrefilterStoreGetName(const uint32_t id) SCMutexUnlock(&g_prefilter_mutex); return name; } -#endif /* PROFILING */ diff --git a/src/detect-engine-prefilter.h b/src/detect-engine-prefilter.h index 7836bab39a..b058cf738e 100644 --- a/src/detect-engine-prefilter.h +++ b/src/detect-engine-prefilter.h @@ -43,9 +43,10 @@ int PrefilterAppendTxEngine(SigGroupHead *sgh, void *pectx, void (*FreeFunc)(void *pectx), const char *name); -void PrefilterFreeEngines(PrefilterEngine *list); +void PrefilterFreeEnginesList(PrefilterEngineList *list); void PrefilterSetupRuleGroup(DetectEngineCtx *de_ctx, SigGroupHead *sgh); +void PrefilterCleanupRuleGroup(SigGroupHead *sgh); #ifdef PROFILING const char *PrefilterStoreGetName(const uint32_t id); diff --git a/src/detect-engine-siggroup.c b/src/detect-engine-siggroup.c index 92d8dc66d4..0c49ef035a 100644 --- a/src/detect-engine-siggroup.c +++ b/src/detect-engine-siggroup.c @@ -64,6 +64,11 @@ void SigGroupHeadInitDataFree(SigGroupHeadInitData *sghid) if (sghid->app_mpms != NULL) { SCFree(sghid->app_mpms); } + + PrefilterFreeEnginesList(sghid->tx_engines); + PrefilterFreeEnginesList(sghid->pkt_engines); + PrefilterFreeEnginesList(sghid->payload_engines); + SCFree(sghid); } @@ -174,10 +179,7 @@ void SigGroupHeadFree(SigGroupHead *sgh) sgh->init = NULL; } - PrefilterFreeEngines(sgh->tx_engines); - PrefilterFreeEngines(sgh->pkt_engines); - PrefilterFreeEngines(sgh->payload_engines); - + PrefilterCleanupRuleGroup(sgh); SCFree(sgh); return; diff --git a/src/detect.h b/src/detect.h index 222bc7620a..b82c9bf53c 100644 --- a/src/detect.h +++ b/src/detect.h @@ -723,8 +723,8 @@ typedef struct DetectEngineCtx_ { struct SCProfileKeywordDetectCtx_ *profile_keyword_ctx_per_list[DETECT_SM_LIST_MAX]; struct SCProfileSghDetectCtx_ *profile_sgh_ctx; uint32_t profile_match_logging_threshold; - uint32_t profile_prefilter_maxid; #endif + uint32_t prefilter_maxid; char config_prefix[64]; @@ -1019,7 +1019,7 @@ typedef struct MpmStore_ { } MpmStore; -typedef struct PrefilterEngine_ { +typedef struct PrefilterEngineList_ { uint16_t id; /** App Proto this engine applies to: only used with Tx Engines */ @@ -1037,15 +1037,39 @@ typedef struct PrefilterEngine_ { Packet *p, Flow *f, void *tx, 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. */ void (*Free)(void *pectx); const char *name; -#ifdef PROFILING - uint32_t profile_id; -#endif + /* global id for this prefilter */ + uint32_t gid; +} 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; typedef struct SigGroupHeadInitData_ { @@ -1060,6 +1084,10 @@ typedef struct SigGroupHeadInitData_ { MpmCtx **app_mpms; + PrefilterEngineList *pkt_engines; + PrefilterEngineList *payload_engines; + PrefilterEngineList *tx_engines; + /* port ptr */ struct DetectPort_ *port; } SigGroupHeadInitData; @@ -1087,11 +1115,6 @@ typedef struct SigGroupHead_ { PrefilterEngine *payload_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 *) */ Signature **match_array;