From: Victor Julien Date: Sun, 15 Sep 2024 10:20:21 +0000 (+0200) Subject: flow: exact flow timeout X-Git-Tag: suricata-8.0.0-beta1~593 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=48301bf28c4927e9816df5ebb63bdfc20a11e1ef;p=thirdparty%2Fsuricata.git flow: exact flow timeout Use a more precise calculation for timing out flows, using both the seconds and the micro seconds. Ticket: #7455. --- diff --git a/src/flow-hash.c b/src/flow-hash.c index 38b4adab91..e0f3a2e6d8 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -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); diff --git a/src/flow-manager.c b/src/flow-manager.c index 99348fc404..2a3d6f6f6a 100644 --- a/src/flow-manager.c +++ b/src/flow-manager.c @@ -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; } diff --git a/src/flow-util.c b/src/flow-util.c index 31e22b9341..9e90ae5be9 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -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); diff --git a/src/flow-util.h b/src/flow-util.h index 368c955d87..4af2e4eafe 100644 --- a/src/flow-util.h +++ b/src/flow-util.h @@ -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; \ diff --git a/src/flow.c b/src/flow.c index aea79d23bf..5508ea7b92 100644 --- a/src/flow.c +++ b/src/flow.c @@ -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 diff --git a/src/flow.h b/src/flow.h index dc3b09afd4..5afbc57012 100644 --- a/src/flow.h +++ b/src/flow.h @@ -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