]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
Improve Signature sorting speed
authorKen Steele <ken@tilera.com>
Sun, 29 Sep 2013 14:45:44 +0000 (10:45 -0400)
committerVictor Julien <victor@inliniac.net>
Mon, 30 Sep 2013 15:39:56 +0000 (17:39 +0200)
Changed the signature sorting code to use a a single merge sort instead
of the multiple pass sorting that was being used. This reduces startup
time on Tile by a factor of 3.

Also replace the user array of pointers to ints with a simpler array of
ints.

src/detect-engine-sigorder.c
src/detect-engine-sigorder.h
src/detect.h

index 5f819858cda32928ba3b9d5c686e9cb23487e075..05b95afcb8fa2f2680dc827904a32991946708a7 100644 (file)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2007-2010 Open Information Security Foundation
+/* Copyright (C) 2007-2013 Open Information Security Foundation
  *
  * You can copy, redistribute or modify this Program under the terms of
  * the GNU General Public License version 2 as published by the Free
@@ -76,18 +76,19 @@ static void SCSigRegisterSignatureOrderingFunc(DetectEngineCtx *de_ctx,
     SCSigOrderFunc *temp = NULL;
 
     curr = de_ctx->sc_sig_order_funcs;
+
+    /* Walk to the end of the list, and leave prev pointing at the
+       last element. */
     prev = curr;
     while (curr != NULL) {
+        if (curr->SWCompare == SWCompare) {
+            /* Already specified this compare */
+            return;
+        }
         prev = curr;
-        if (curr->SWCompare == SWCompare)
-            break;
-
         curr = curr->next;
     }
 
-    if (curr != NULL)
-        return;
-
     if ( (temp = SCMalloc(sizeof(SCSigOrderFunc))) == NULL) {
         SCLogError(SC_ERR_FATAL, "Fatal error encountered in SCSigRegisterSignatureOrderingFunc. Exiting...");
         exit(EXIT_FAILURE);
@@ -96,6 +97,7 @@ static void SCSigRegisterSignatureOrderingFunc(DetectEngineCtx *de_ctx,
 
     temp->SWCompare = SWCompare;
 
+    /* Append the new compare function at the end of the list. */
     if (prev == NULL)
         de_ctx->sc_sig_order_funcs = temp;
     else
@@ -346,9 +348,7 @@ static inline int SCSigGetPktvarType(Signature *sig)
  */
 static inline void SCSigProcessUserDataForFlowbits(SCSigSignatureWrapper *sw)
 {
-    *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWBITS])) = SCSigGetFlowbitsType(sw->sig);
-
-    return;
+    sw->user[SC_RADIX_USER_DATA_FLOWBITS] = SCSigGetFlowbitsType(sw->sig);
 }
 
 /**
@@ -360,16 +360,12 @@ static inline void SCSigProcessUserDataForFlowbits(SCSigSignatureWrapper *sw)
  */
 static inline void SCSigProcessUserDataForFlowvar(SCSigSignatureWrapper *sw)
 {
-    *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWVAR])) = SCSigGetFlowvarType(sw->sig);
-
-    return;
+    sw->user[SC_RADIX_USER_DATA_FLOWVAR] = SCSigGetFlowvarType(sw->sig);
 }
 
 static inline void SCSigProcessUserDataForFlowint(SCSigSignatureWrapper *sw)
 {
-    *((int *)(sw->user[SC_RADIX_USER_DATA_FLOWINT])) = SCSigGetFlowintType(sw->sig);
-
-    return;
+    sw->user[SC_RADIX_USER_DATA_FLOWINT] = SCSigGetFlowintType(sw->sig);
 }
 
 /**
@@ -381,110 +377,92 @@ static inline void SCSigProcessUserDataForFlowint(SCSigSignatureWrapper *sw)
  */
 static inline void SCSigProcessUserDataForPktvar(SCSigSignatureWrapper *sw)
 {
-    *((int *)(sw->user[SC_RADIX_USER_DATA_PKTVAR])) = SCSigGetPktvarType(sw->sig);
-
-    return;
+    sw->user[SC_RADIX_USER_DATA_PKTVAR] = SCSigGetPktvarType(sw->sig);
 }
 
-static void SCSigOrder(DetectEngineCtx *de_ctx,
-                       SCSigSignatureWrapper *sw,
-                       int (*SWCompare)(SCSigSignatureWrapper *sw1, SCSigSignatureWrapper *sw2))
+/* Return 1 if sw1 comes before sw2 in the final list. */
+static int SCSigLessThan(SCSigSignatureWrapper *sw1,
+                         SCSigSignatureWrapper *sw2,
+                         SCSigOrderFunc *cmp_func_list)
 {
-    SCSigSignatureWrapper *min = NULL;
-    SCSigSignatureWrapper *max = NULL;
-    SCSigSignatureWrapper *prev = NULL;
+    SCSigOrderFunc *funcs = cmp_func_list;
 
-    if (sw == NULL)
-        return;
+    while (funcs != NULL) {
+        int delta = funcs->SWCompare(sw1, sw2);
+        if (delta > 0)
+            return 1;
+        else if (delta < 0)
+            return 0;
 
-    if (de_ctx->sc_sig_sig_wrapper == NULL) {
-        de_ctx->sc_sig_sig_wrapper = sw;
-        sw->min = NULL;
-        sw->max = NULL;
-        return;
+        funcs = funcs->next;
     }
+    // They are equal, so use sid as the final decider.
+    return sw1->sig->id < sw2->sig->id;
+}
 
-    min = sw->min;
-    max = sw->max;
-    if (min == NULL)
-        min = de_ctx->sc_sig_sig_wrapper;
-    else
-        min = min->next;
-
-    while (min != max) {
-        prev = min;
-        /* the sorting logic */
-        if (SWCompare(sw, min) <= 0) {
-            min = min->next;
-            continue;
-        }
-
-        if (min->prev == sw)
+/* Merge sort based on a list of compare functions */
+static SCSigSignatureWrapper *SCSigOrder(SCSigSignatureWrapper *sw,
+                                         SCSigOrderFunc *cmp_func_list)
+{
+    SCSigSignatureWrapper *subA = NULL;
+    SCSigSignatureWrapper *subB = NULL;
+    SCSigSignatureWrapper *first;
+    SCSigSignatureWrapper *second;
+    SCSigSignatureWrapper *result = NULL;
+    SCSigSignatureWrapper *last = NULL;
+    SCSigSignatureWrapper *new = NULL;
+
+    /* Divide input list into two sub-lists. */
+    while (sw != NULL) {
+        first = sw;
+        sw = sw->next;
+        /* Push the first element onto sub-list A */
+        first->next = subA;
+        subA = first;
+
+        if (sw == NULL)
             break;
-
-        if (sw->next != NULL)
-            sw->next->prev = sw->prev;
-        if (sw->prev != NULL)
-            sw->prev->next = sw->next;
-        if (de_ctx->sc_sig_sig_wrapper == sw)
-            de_ctx->sc_sig_sig_wrapper = sw->next;
-
-        sw->next = min;
-        sw->prev = min->prev;
-
-        if (min->prev != NULL)
-            min->prev->next = sw;
-        else
-            de_ctx->sc_sig_sig_wrapper = sw;
-
-        min->prev = sw;
-
-        break;
-    }
-
-    if (min == max && prev != sw) {
-        if (sw->next != NULL) {
-            sw->next->prev = sw->prev;
-        }
-        if (sw->prev != NULL) {
-            sw->prev->next = sw->next;
+        second = sw;
+        sw = sw->next;
+        /* Push the second element onto sub-list B */
+        second->next = subB;
+        subB = second;
+    }
+    if (subB == NULL) {
+        /* Only zero or one element on the list. */
+        return subA;
+    }
+
+    /* Now sort each list */
+    subA = SCSigOrder(subA, cmp_func_list);
+    subB = SCSigOrder(subB, cmp_func_list);
+
+    /* Merge the two sorted lists. */
+    while (subA != NULL && subB != NULL) {
+        if (SCSigLessThan(subA, subB, cmp_func_list)) {
+            new = subA;
+            subA = subA->next;
+        } else {
+          new = subB;
+          subB = subB->next;
         }
-
-        if (min == NULL) {
-            if (prev != NULL)
-                prev->next = sw;
-            sw->prev = prev;
-            sw->next = NULL;
+        /* Push onto the end of the output list. */
+        new->next = NULL;
+        if (result == NULL) {
+            result = new;
+            last = new;
         } else {
-            sw->prev = min->prev;
-            sw->next = min;
-            if (min->prev != NULL)
-                min->prev->next = sw;
-            min->prev = sw;
+            last->next = new;
+            last = new;
         }
     }
+    /* Attach the rest of any remaining list. Only one can be non-NULL here. */
+    if (subA == NULL)
+        last->next = subB;
+    else if (subB == NULL)
+        last->next = subA;
 
-    /* set the min signature for this keyword, for the next ordering function */
-    min = sw;
-    while (min != NULL && min != sw->min) {
-        if (SWCompare(sw, min) != 0)
-            break;
-
-        min = min->prev;
-    }
-    sw->min = min;
-
-    /* set the max signature for this keyword + 1, for the next ordering func */
-    max = sw;
-    while (max != NULL && max != sw->max) {
-        if (SWCompare(max, sw) != 0)
-            break;
-
-        max = max->next;
-    }
-    sw->max = max;
-
-    return;
+    return result;
 }
 
 /**
@@ -510,8 +488,8 @@ static int SCSigOrderByActionCompare(SCSigSignatureWrapper *sw1,
 static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1,
                                        SCSigSignatureWrapper *sw2)
 {
-    return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWBITS]) -
-        *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWBITS]);
+    return sw1->user[SC_RADIX_USER_DATA_FLOWBITS] -
+        sw2->user[SC_RADIX_USER_DATA_FLOWBITS];
 }
 
 /**
@@ -524,8 +502,8 @@ static int SCSigOrderByFlowbitsCompare(SCSigSignatureWrapper *sw1,
 static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1,
                                       SCSigSignatureWrapper *sw2)
 {
-    return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWVAR]) -
-        *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWVAR]);
+    return sw1->user[SC_RADIX_USER_DATA_FLOWVAR] -
+        sw2->user[SC_RADIX_USER_DATA_FLOWVAR];
 }
 
 /**
@@ -538,15 +516,15 @@ static int SCSigOrderByFlowvarCompare(SCSigSignatureWrapper *sw1,
 static int SCSigOrderByPktvarCompare(SCSigSignatureWrapper *sw1,
                                      SCSigSignatureWrapper *sw2)
 {
-    return *((int *)sw1->user[SC_RADIX_USER_DATA_PKTVAR]) -
-        *((int *)sw2->user[SC_RADIX_USER_DATA_PKTVAR]);
+    return sw1->user[SC_RADIX_USER_DATA_PKTVAR] -
+        sw2->user[SC_RADIX_USER_DATA_PKTVAR];
 }
 
 static int SCSigOrderByFlowintCompare(SCSigSignatureWrapper *sw1,
                                       SCSigSignatureWrapper *sw2)
 {
-    return *((int *)sw1->user[SC_RADIX_USER_DATA_FLOWINT]) -
-        *((int *)sw2->user[SC_RADIX_USER_DATA_FLOWINT]);
+    return sw1->user[SC_RADIX_USER_DATA_FLOWINT] -
+        sw2->user[SC_RADIX_USER_DATA_FLOWINT];
 }
 
 /**
@@ -572,7 +550,6 @@ static int SCSigOrderByPriorityCompare(SCSigSignatureWrapper *sw1,
 static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig)
 {
     SCSigSignatureWrapper *sw = NULL;
-    int i = 0;
 
     if ( (sw = SCMalloc(sizeof(SCSigSignatureWrapper))) == NULL)
         return NULL;
@@ -580,20 +557,6 @@ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig)
 
     sw->sig = sig;
 
-    if ( (sw->user = SCMalloc(SC_RADIX_USER_DATA_MAX * sizeof(int *))) == NULL) {
-        SCFree(sw);
-        return NULL;
-    }
-    memset(sw->user, 0, SC_RADIX_USER_DATA_MAX * sizeof(int *));
-
-    for (i = 0; i < SC_RADIX_USER_DATA_MAX; i++) {
-        if ( (sw->user[i] = SCMalloc(sizeof(int))) == NULL) {
-            SCFree(sw);
-            return NULL;
-        }
-        memset(sw->user[i], 0, sizeof(int));
-    }
-
     /* Process data from the signature into a cache for further use by the
      * sig_ordering module */
     SCSigProcessUserDataForFlowbits(sw);
@@ -612,51 +575,51 @@ static inline SCSigSignatureWrapper *SCSigAllocSignatureWrapper(Signature *sig)
  */
 void SCSigOrderSignatures(DetectEngineCtx *de_ctx)
 {
-    SCSigOrderFunc *funcs = NULL;
     Signature *sig = NULL;
     SCSigSignatureWrapper *sigw = NULL;
+    SCSigSignatureWrapper *sigw_list = NULL;
 
     int i = 0;
     SCLogDebug("ordering signatures in memory");
 
     sig = de_ctx->sig_list;
     while (sig != NULL) {
-        i++;
         sigw = SCSigAllocSignatureWrapper(sig);
-        funcs = de_ctx->sc_sig_order_funcs;
-        while (funcs != NULL) {
-            SCSigOrder(de_ctx, sigw, funcs->SWCompare);
+        /* Push signature wrapper onto a list, order doesn't matter here. */
+        sigw->next = sigw_list;
+        sigw_list = sigw;
 
-            funcs = funcs->next;
-        }
         sig = sig->next;
+        i++;
     }
 
+    /* Sort the list */
+    sigw_list = SCSigOrder(sigw_list, de_ctx->sc_sig_order_funcs);
+
     SCLogDebug("Total Signatures to be processed by the"
            "sigordering module: %d", i);
 
-    /* Re-order it in the Detection Engine Context sig_list */
+    /* Recreate the sig list in order */
     de_ctx->sig_list = NULL;
-    sigw = de_ctx->sc_sig_sig_wrapper;
+    sigw = sigw_list;
     i = 0;
     while (sigw != NULL) {
         i++;
+        sigw->sig->next = NULL;
         if (de_ctx->sig_list == NULL) {
-            sigw->sig->next = NULL;
+            /* First entry on the list */
             de_ctx->sig_list = sigw->sig;
             sig = de_ctx->sig_list;
-            sigw = sigw->next;
-            continue;
+        } else {
+            sig->next = sigw->sig;
+            sig = sig->next;
         }
-
-        sigw->sig->next = NULL;
-        sig->next = sigw->sig;
-        sig = sig->next;
+        SCSigSignatureWrapper *sigw_to_free = sigw;
         sigw = sigw->next;
+        SCFree(sigw_to_free);
     }
 
     SCLogDebug("total signatures reordered by the sigordering module: %d", i);
-    return;
 }
 
 /**
@@ -680,8 +643,6 @@ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx)
     SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByFlowvarCompare);
     SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPktvarCompare);
     SCSigRegisterSignatureOrderingFunc(de_ctx, SCSigOrderByPriorityCompare);
-
-    return;
 }
 
 /**
@@ -692,11 +653,8 @@ void SCSigRegisterSignatureOrderingFuncs(DetectEngineCtx *de_ctx)
  */
 void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx)
 {
-    SCSigOrderFunc *funcs = NULL;
-    SCSigSignatureWrapper *sigw = NULL;
-    SCSigSignatureWrapper *prev = NULL;
-    void *temp = NULL;
-    uint8_t i;
+    SCSigOrderFunc *funcs;
+    void *temp;
 
     /* clean the memory alloted to the signature ordering funcs */
     funcs = de_ctx->sc_sig_order_funcs;
@@ -706,23 +664,6 @@ void SCSigSignatureOrderingModuleCleanup(DetectEngineCtx *de_ctx)
         SCFree(temp);
     }
     de_ctx->sc_sig_order_funcs = NULL;
-
-    /* clean the memory alloted to the signature wrappers */
-    sigw = de_ctx->sc_sig_sig_wrapper;
-    while (sigw != NULL) {
-        prev = sigw;
-        sigw = sigw->next;
-        for (i = 0; i < SC_RADIX_USER_DATA_MAX; i++) {
-            if (prev->user[i] != NULL) {
-                SCFree(prev->user[i]);
-            }
-        }
-        SCFree(prev->user);
-        SCFree(prev);
-    }
-    de_ctx->sc_sig_sig_wrapper = NULL;
-
-    return;
 }
 
 /**********Unittests**********/
@@ -2069,6 +2010,4 @@ void SCSigRegisterSignatureOrderingTests(void)
     UtRegisterTest("SCSigOrderingTest11", SCSigOrderingTest11, 1);
     UtRegisterTest("SCSigOrderingTest12", SCSigOrderingTest12, 1);
 #endif
-
-    return;
 }
index aed51d8dbd7bee9510b74035bd3ac0febf87dc8e..1451dfc3fae3e9ad1495ad7482e8ad9db6fadd79 100644 (file)
@@ -54,7 +54,7 @@ typedef struct SCSigSignatureWrapper_ {
     struct SCSigSignatureWrapper_ *max;
 
     /* user data that is to be associated with this sigwrapper */
-    int **user;
+    int user[SC_RADIX_USER_DATA_MAX];
 
     struct SCSigSignatureWrapper_ *next;
     struct SCSigSignatureWrapper_ *prev;
index c08103512653910c51a5267da1ad5783b3b6fda9..9645f7e7a86e96e6dab2289131c2f835b31161be 100644 (file)
@@ -591,7 +591,6 @@ typedef struct DetectEngineCtx_ {
 
     /* used by the signature ordering module */
     struct SCSigOrderFunc_ *sc_sig_order_funcs;
-    struct SCSigSignatureWrapper_ *sc_sig_sig_wrapper;
 
     /* hash table used for holding the classification config info */
     HashTable *class_conf_ht;