From: Victor Julien Date: Wed, 18 Sep 2024 20:19:17 +0000 (+0200) Subject: flow: skip lock for skippable flows X-Git-Tag: suricata-8.0.0-beta1~584 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=14864cda59b4fa92754f20079f4c2316403fbc9a;p=thirdparty%2Fsuricata.git flow: skip lock for skippable flows Some checks can be done w/o holding a lock: - seeing if the flow matches the packet - if the hash row needs a timeout check This patch skips taking a lock in these conditions. --- diff --git a/src/flow-hash.c b/src/flow-hash.c index da494199d7..c08b6e12c7 100644 --- a/src/flow-hash.c +++ b/src/flow-hash.c @@ -926,39 +926,42 @@ Flow *FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow const uint16_t tv_id = GetTvId(tv); const bool emerg = (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0; const uint32_t fb_nextts = !emerg ? SC_ATOMIC_GET(fb->next_ts) : 0; + const bool timeout_check = (fb_nextts <= (uint32_t)SCTIME_SECS(p->ts)); /* ok, we have a flow in the bucket. Let's find out if it is our flow */ Flow *prev_f = NULL; /* previous flow */ f = fb->head; do { Flow *next_f = NULL; - FLOWLOCK_WRLOCK(f); - const bool timedout = (fb_nextts <= (uint32_t)SCTIME_SECS(p->ts) && - FlowIsTimedOut(tv_id, f, p->ts, emerg)); - if (timedout) { - next_f = f->next; - MoveToWorkQueue(tv, fls, fb, f, prev_f); - FLOWLOCK_UNLOCK(f); - goto flow_removed; - } else if (FlowCompare(f, p) != 0) { - /* found a matching flow that is not timed out */ - if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx))) { - Flow *new_f = TcpReuseReplace(tv, fls, fb, f, hash, p); - if (prev_f == NULL) /* if we have no prev it means new_f is now our prev */ - prev_f = new_f; - MoveToWorkQueue(tv, fls, fb, f, prev_f); /* evict old flow */ - FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */ - - if (new_f == NULL) { - FBLOCK_UNLOCK(fb); - return NULL; + const bool our_flow = FlowCompare(f, p) != 0; + if (our_flow || timeout_check) { + FLOWLOCK_WRLOCK(f); + const bool timedout = (timeout_check && FlowIsTimedOut(tv_id, f, p->ts, emerg)); + if (timedout) { + next_f = f->next; + MoveToWorkQueue(tv, fls, fb, f, prev_f); + FLOWLOCK_UNLOCK(f); + goto flow_removed; + } else if (our_flow) { + /* found a matching flow that is not timed out */ + if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx))) { + Flow *new_f = TcpReuseReplace(tv, fls, fb, f, hash, p); + if (prev_f == NULL) /* if we have no prev it means new_f is now our prev */ + prev_f = new_f; + MoveToWorkQueue(tv, fls, fb, f, prev_f); /* evict old flow */ + FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */ + + if (new_f == NULL) { + FBLOCK_UNLOCK(fb); + return NULL; + } + f = new_f; } - f = new_f; + FlowReference(dest, f); + FBLOCK_UNLOCK(fb); + return f; /* return w/o releasing flow lock */ + } else { + FLOWLOCK_UNLOCK(f); } - FlowReference(dest, f); - FBLOCK_UNLOCK(fb); - return f; /* return w/o releasing flow lock */ - } else { - FLOWLOCK_UNLOCK(f); } /* unless we removed 'f', prev_f needs to point to * current 'f' when adding a new flow below. */