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.
pull/12371/head
Victor Julien 2 years ago committed by Victor Julien
parent 2af67e17bc
commit 14864cda59

@ -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. */

Loading…
Cancel
Save