]> git.ipfire.org Git - thirdparty/suricata.git/commitdiff
flow: exact flow timeout
authorVictor Julien <vjulien@oisf.net>
Sun, 15 Sep 2024 10:20:21 +0000 (12:20 +0200)
committerVictor Julien <victor@inliniac.net>
Fri, 10 Jan 2025 08:16:36 +0000 (09:16 +0100)
Use a more precise calculation for timing out flows, using both the
seconds and the micro seconds.

Ticket: #7455.

src/flow-hash.c
src/flow-manager.c
src/flow-util.c
src/flow-util.h
src/flow.c
src/flow.h

index 38b4adab91189d4536d184a682e8bd05f6edb3a0..e0f3a2e6d8c2d260bbd0852578826ae25f776036 100644 (file)
@@ -764,8 +764,6 @@ static Flow *TcpReuseReplace(ThreadVars *tv, FlowLookupStruct *fls, FlowBucket *
 #ifdef UNITTESTS
     }
 #endif
-    /* time out immediately */
-    old_f->timeout_at = 0;
     /* get some settings that we move over to the new flow */
     FlowThreadId thread_id[2] = { old_f->thread_id[0], old_f->thread_id[1] };
     old_f->flow_end_flags |= FLOW_END_FLAG_TCPREUSE;
@@ -833,19 +831,21 @@ static inline void MoveToWorkQueue(ThreadVars *tv, FlowLookupStruct *fls,
     }
 }
 
-static inline bool FlowIsTimedOut(const Flow *f, const uint32_t sec, const bool emerg)
+static inline bool FlowIsTimedOut(const Flow *f, const SCTime_t ts, const bool emerg)
 {
-    if (unlikely(f->timeout_at < sec)) {
-        return true;
-    } else if (unlikely(emerg)) {
-        extern FlowProtoTimeout flow_timeouts_delta[FLOW_PROTO_MAX];
-
-        int64_t timeout_at = f->timeout_at -
-            FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap);
-        if ((int64_t)sec >= timeout_at)
-            return true;
+    SCTime_t timesout_at;
+    if (emerg) {
+        extern FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX];
+        timesout_at = SCTIME_ADD_SECS(f->lastts,
+                FlowGetFlowTimeoutDirect(flow_timeouts_emerg, f->flow_state, f->protomap));
+    } else {
+        timesout_at = SCTIME_ADD_SECS(f->lastts, f->timeout_policy);
     }
-    return false;
+    /* do the timeout check */
+    if (SCTIME_CMP_LT(ts, timesout_at)) {
+        return false;
+    }
+    return true;
 }
 
 /** \brief Get Flow for packet
@@ -907,8 +907,8 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow
     do {
         Flow *next_f = NULL;
         FLOWLOCK_WRLOCK(f);
-        const bool timedout = (fb_nextts < (uint32_t)SCTIME_SECS(p->ts) &&
-                               FlowIsTimedOut(f, (uint32_t)SCTIME_SECS(p->ts), emerg));
+        const bool timedout =
+                (fb_nextts < (uint32_t)SCTIME_SECS(p->ts) && FlowIsTimedOut(f, p->ts, emerg));
         if (timedout) {
             next_f = f->next;
             MoveToWorkQueue(tv, fls, fb, f, prev_f);
index 99348fc40413ee279b69cd695c005e8be08fc791..2a3d6f6f6a226534950d05674e432a7c43a478ef 100644 (file)
@@ -174,6 +174,9 @@ again:
 
 /** \internal
  *  \brief check if a flow is timed out
+ *  Takes lastts, adds the timeout policy to it, compared to current time `ts`.
+ *  In case of emergency mode, timeout_policy is ignored and the emerg table
+ *  is used.
  *
  *  \param f flow
  *  \param ts timestamp
@@ -183,16 +186,20 @@ again:
  */
 static bool FlowManagerFlowTimeout(Flow *f, SCTime_t ts, uint32_t *next_ts, const bool emerg)
 {
-    uint32_t flow_times_out_at = f->timeout_at;
+    SCTime_t timesout_at;
+
     if (emerg) {
-        extern FlowProtoTimeout flow_timeouts_delta[FLOW_PROTO_MAX];
-        flow_times_out_at -= FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap);
+        extern FlowProtoTimeout flow_timeouts_emerg[FLOW_PROTO_MAX];
+        timesout_at = SCTIME_ADD_SECS(f->lastts,
+                FlowGetFlowTimeoutDirect(flow_timeouts_emerg, f->flow_state, f->protomap));
+    } else {
+        timesout_at = SCTIME_ADD_SECS(f->lastts, f->timeout_policy);
     }
-    if (*next_ts == 0 || flow_times_out_at < *next_ts)
-        *next_ts = flow_times_out_at;
+    if (*next_ts == 0 || (uint32_t)SCTIME_SECS(timesout_at) < *next_ts)
+        *next_ts = (uint32_t)SCTIME_SECS(timesout_at);
 
     /* do the timeout check */
-    if ((uint64_t)flow_times_out_at >= SCTIME_SECS(ts)) {
+    if (SCTIME_CMP_LT(ts, timesout_at)) {
         return false;
     }
 
index 31e22b9341ac1a8ba093d86fe149685a18448e32..9e90ae5be9bc07649036bb86e09332aa1da47673 100644 (file)
@@ -195,8 +195,6 @@ void FlowInit(ThreadVars *tv, Flow *f, const Packet *p)
 
     f->protomap = FlowGetProtoMapping(f->proto);
     f->timeout_policy = FlowGetTimeoutPolicy(f);
-    const uint32_t timeout_at = (uint32_t)SCTIME_SECS(f->startts) + f->timeout_policy;
-    f->timeout_at = timeout_at;
 
     if (MacSetFlowStorageEnabled()) {
         DEBUG_VALIDATE_BUG_ON(FlowGetStorageById(f, MacSetGetFlowStorageID()) != NULL);
index 368c955d876a50279ddccd7ebea21142395dfac8..4af2e4eafe0faccc8521397ce95b13a3c3e9d24c 100644 (file)
@@ -41,7 +41,6 @@
         (f)->dp = 0;                                                                               \
         (f)->proto = 0;                                                                            \
         (f)->livedev = NULL;                                                                       \
-        (f)->timeout_at = 0;                                                                       \
         (f)->timeout_policy = 0;                                                                   \
         (f)->vlan_idx = 0;                                                                         \
         (f)->next = NULL;                                                                          \
@@ -88,7 +87,6 @@
         (f)->vlan_idx = 0;                                                                         \
         (f)->ffr = 0;                                                                              \
         (f)->next = NULL;                                                                          \
-        (f)->timeout_at = 0;                                                                       \
         (f)->timeout_policy = 0;                                                                   \
         (f)->flow_state = 0;                                                                       \
         (f)->tenant_id = 0;                                                                        \
index aea79d23bf086fa011ec3e1c10382f63ae929c9e..5508ea7b923e153b7a20cccd55c6719fb59fc6ab 100644 (file)
@@ -397,10 +397,6 @@ void FlowHandlePacketUpdate(Flow *f, Packet *p, ThreadVars *tv, DecodeThreadVars
         /* update the last seen timestamp of this flow */
         if (SCTIME_CMP_GT(p->ts, f->lastts)) {
             f->lastts = p->ts;
-            const uint32_t timeout_at = (uint32_t)SCTIME_SECS(f->lastts) + f->timeout_policy;
-            if (timeout_at != f->timeout_at) {
-                f->timeout_at = timeout_at;
-            }
         }
 #ifdef CAPTURE_OFFLOAD
     } else {
@@ -1169,9 +1165,6 @@ void FlowUpdateState(Flow *f, const enum FlowState s)
         const uint32_t timeout_policy = FlowGetTimeoutPolicy(f);
         if (timeout_policy != f->timeout_policy) {
             f->timeout_policy = timeout_policy;
-            const uint32_t timeout_at = (uint32_t)SCTIME_SECS(f->lastts) + timeout_policy;
-            if (timeout_at != f->timeout_at)
-                f->timeout_at = timeout_at;
         }
     }
 #ifdef UNITTESTS
index dc3b09afd47f0956c4324747d4d41b0db9ff4c12..5afbc57012adb291c7e4d10dd1bb1a47721e8d05 100644 (file)
@@ -391,11 +391,6 @@ typedef struct Flow_
         uint8_t ffr;
     };
 
-    /** timestamp in seconds of the moment this flow will timeout
-     *  according to the timeout policy. Does *not* take emergency
-     *  mode into account. */
-    uint32_t timeout_at;
-
     /** Thread ID for the stream/detect portion of this flow */
     FlowThreadId thread_id[2];
 
@@ -406,8 +401,8 @@ typedef struct Flow_
     /** flow hash - the flow hash before hash table size mod. */
     uint32_t flow_hash;
 
-    /** timeout policy value in seconds to add to the lastts.tv_sec
-     *  when a packet has been received. */
+    /** timeout in seconds by policy, add to Flow::lastts to get actual time this times out.
+     * Ignored in emergency mode. */
     uint32_t timeout_policy;
 
     /* time stamp of last update (last packet). Set/updated under the