]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
flow: fix flow logging at shutdown
authorVictor Julien <victor@inliniac.net>
Tue, 30 Sep 2014 13:24:24 +0000 (15:24 +0200)
committerVictor Julien <victor@inliniac.net>
Wed, 1 Oct 2014 07:00:19 +0000 (09:00 +0200)
Move all flows from the hash to the recycler at shutdown.

Bug #1260

src/flow-manager.c

index e663f568f0787b23dd6d9586f917db0d9f8b4ff1..2b2f939dae1d43d0c6efca3463c1cb6655a45f28 100644 (file)
@@ -395,6 +395,87 @@ next:
     return cnt;
 }
 
+/**
+ *  \internal
+ *
+ *  \brief move all flows out of a hash row
+ *
+ *  \param f last flow in the hash row
+ *
+ *  \retval cnt removed out flows
+ */
+static uint32_t FlowManagerHashRowCleanup(Flow *f)
+{
+    uint32_t cnt = 0;
+
+    do {
+        FLOWLOCK_WRLOCK(f);
+
+        Flow *next_flow = f->hprev;
+
+        int state = FlowGetFlowState(f);
+
+        /* remove from the hash */
+        if (f->hprev != NULL)
+            f->hprev->hnext = f->hnext;
+        if (f->hnext != NULL)
+            f->hnext->hprev = f->hprev;
+        if (f->fb->head == f)
+            f->fb->head = f->hnext;
+        if (f->fb->tail == f)
+            f->fb->tail = f->hprev;
+
+        f->hnext = NULL;
+        f->hprev = NULL;
+
+        if (state == FLOW_STATE_NEW)
+            f->flow_end_flags |= FLOW_END_FLAG_STATE_NEW;
+        else if (state == FLOW_STATE_ESTABLISHED)
+            f->flow_end_flags |= FLOW_END_FLAG_STATE_ESTABLISHED;
+        else if (state == FLOW_STATE_CLOSED)
+            f->flow_end_flags |= FLOW_END_FLAG_STATE_CLOSED;
+
+        f->flow_end_flags |= FLOW_END_FLAG_TIMEOUT;
+
+        /* no one is referring to this flow, use_cnt 0, removed from hash
+         * so we can unlock it and move it to the recycle queue. */
+        FLOWLOCK_UNLOCK(f);
+
+        FlowEnqueue(&flow_recycle_q, f);
+
+        cnt++;
+
+        f = next_flow;
+    } while (f != NULL);
+
+    return cnt;
+}
+
+/**
+ *  \brief remove all flows from the hash
+ *
+ *  \retval cnt number of removes out flows
+ */
+static uint32_t FlowCleanupHash(void){
+    uint32_t idx = 0;
+    uint32_t cnt = 0;
+
+    for (idx = 0; idx < flow_config.hash_size; idx++) {
+        FlowBucket *fb = &flow_hash[idx];
+
+        FBLOCK_LOCK(fb);
+
+        if (fb->tail != NULL) {
+            /* we have a flow, or more than one */
+            cnt += FlowManagerHashRowCleanup(fb->tail);
+        }
+
+        FBLOCK_UNLOCK(fb);
+    }
+
+    return cnt;
+}
+
 extern int g_detect_disabled;
 
 typedef struct FlowManagerThreadData_ {
@@ -837,6 +918,9 @@ void FlowKillFlowRecyclerThread(void)
     ThreadVars *tv = NULL;
     int cnt = 0;
 
+    /* move all flows still in the hash to the recycler queue */
+    FlowCleanupHash();
+
     /* make sure all flows are processed */
     do {
         SCCtrlCondSignal(&flow_recycler_ctrl_cond);