|
|
|
@ -1,4 +1,4 @@
|
|
|
|
/* Copyright (C) 2007-2020 Open Information Security Foundation
|
|
|
|
/* Copyright (C) 2007-2025 Open Information Security Foundation
|
|
|
|
*
|
|
|
|
*
|
|
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
|
|
* You can copy, redistribute or modify this Program under the terms of
|
|
|
|
* the GNU General Public License version 2 as published by the Free
|
|
|
|
* the GNU General Public License version 2 as published by the Free
|
|
|
|
@ -39,13 +39,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
#include "conf.h"
|
|
|
|
#include "conf.h"
|
|
|
|
|
|
|
|
|
|
|
|
Packet *TmqhInputFlow(ThreadVars *t);
|
|
|
|
PacketQueueNoLock TmqhInputFlow(ThreadVars *t);
|
|
|
|
void TmqhOutputFlowHash(ThreadVars *t, Packet *p);
|
|
|
|
void TmqhOutputFlowHash(ThreadVars *t, Packet *p);
|
|
|
|
void TmqhOutputFlowIPPair(ThreadVars *t, Packet *p);
|
|
|
|
void TmqhOutputFlowIPPair(ThreadVars *t, Packet *p);
|
|
|
|
static void TmqhOutputFlowFTPHash(ThreadVars *t, Packet *p);
|
|
|
|
static void TmqhOutputFlowFTPHash(ThreadVars *t, Packet *p);
|
|
|
|
|
|
|
|
static void TmqhOutputFlush(ThreadVars *tv);
|
|
|
|
void *TmqhOutputFlowSetupCtx(const char *queue_str);
|
|
|
|
void *TmqhOutputFlowSetupCtx(const char *queue_str);
|
|
|
|
void TmqhOutputFlowFreeCtx(void *ctx);
|
|
|
|
void TmqhOutputFlowFreeCtx(void *ctx);
|
|
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
void TmqhFlowRegisterTests(void);
|
|
|
|
void TmqhFlowRegisterTests(void);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static uint16_t g_sync_pkts = 8;
|
|
|
|
|
|
|
|
|
|
|
|
void TmqhFlowRegister(void)
|
|
|
|
void TmqhFlowRegister(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@ -53,8 +58,9 @@ void TmqhFlowRegister(void)
|
|
|
|
tmqh_table[TMQH_FLOW].InHandler = TmqhInputFlow;
|
|
|
|
tmqh_table[TMQH_FLOW].InHandler = TmqhInputFlow;
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandlerCtxSetup = TmqhOutputFlowSetupCtx;
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandlerCtxSetup = TmqhOutputFlowSetupCtx;
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandlerCtxFree = TmqhOutputFlowFreeCtx;
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandlerCtxFree = TmqhOutputFlowFreeCtx;
|
|
|
|
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
tmqh_table[TMQH_FLOW].RegisterTests = TmqhFlowRegisterTests;
|
|
|
|
tmqh_table[TMQH_FLOW].RegisterTests = TmqhFlowRegisterTests;
|
|
|
|
|
|
|
|
#endif
|
|
|
|
const char *scheduler = NULL;
|
|
|
|
const char *scheduler = NULL;
|
|
|
|
if (SCConfGetNonNull("autofp-scheduler", &scheduler) == 1) {
|
|
|
|
if (SCConfGetNonNull("autofp-scheduler", &scheduler) == 1) {
|
|
|
|
if (strcasecmp(scheduler, "round-robin") == 0) {
|
|
|
|
if (strcasecmp(scheduler, "round-robin") == 0) {
|
|
|
|
@ -78,13 +84,19 @@ void TmqhFlowRegister(void)
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash;
|
|
|
|
tmqh_table[TMQH_FLOW].OutHandler = TmqhOutputFlowHash;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
intmax_t sync_pkts;
|
|
|
|
|
|
|
|
if (SCConfGetInt("autofp-batch-size", &sync_pkts) != 1)
|
|
|
|
|
|
|
|
sync_pkts = 8;
|
|
|
|
|
|
|
|
g_sync_pkts = (uint16_t)sync_pkts;
|
|
|
|
|
|
|
|
SCLogNotice("autofp-block-size: %u", g_sync_pkts);
|
|
|
|
|
|
|
|
tmqh_table[TMQH_FLOW].OutFlush = TmqhOutputFlush;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TmqhFlowPrintAutofpHandler(void)
|
|
|
|
void TmqhFlowPrintAutofpHandler(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#define PRINT_IF_FUNC(f, msg) \
|
|
|
|
#define PRINT_IF_FUNC(f, msg) \
|
|
|
|
if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \
|
|
|
|
if (tmqh_table[TMQH_FLOW].OutHandler == (f)) \
|
|
|
|
SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg))
|
|
|
|
SCLogConfig("AutoFP mode using \"%s\" flow load balancer", (msg))
|
|
|
|
|
|
|
|
|
|
|
|
PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash");
|
|
|
|
PRINT_IF_FUNC(TmqhOutputFlowHash, "Hash");
|
|
|
|
PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair");
|
|
|
|
PRINT_IF_FUNC(TmqhOutputFlowIPPair, "IPPair");
|
|
|
|
@ -94,27 +106,21 @@ void TmqhFlowPrintAutofpHandler(void)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* same as 'simple' */
|
|
|
|
/* same as 'simple' */
|
|
|
|
Packet *TmqhInputFlow(ThreadVars *tv)
|
|
|
|
PacketQueueNoLock TmqhInputFlow(ThreadVars *tv)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
PacketQueue *q = tv->inq->pq;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
StatsSyncCountersIfSignalled(&tv->stats);
|
|
|
|
StatsSyncCountersIfSignalled(&tv->stats);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PacketQueue *q = tv->inq->pq;
|
|
|
|
SCMutexLock(&q->mutex_q);
|
|
|
|
SCMutexLock(&q->mutex_q);
|
|
|
|
if (q->len == 0) {
|
|
|
|
if (q->len == 0) {
|
|
|
|
/* if we have no packets in queue, wait... */
|
|
|
|
/* if we have no packets in queue, wait... */
|
|
|
|
SCCondWait(&q->cond_q, &q->mutex_q);
|
|
|
|
SCCondWait(&q->cond_q, &q->mutex_q);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PacketQueueNoLock pq = { .top = q->top, .bot = q->bot, q->len };
|
|
|
|
if (q->len > 0) {
|
|
|
|
q->bot = q->top = NULL;
|
|
|
|
Packet *p = PacketDequeue(q);
|
|
|
|
q->len = 0;
|
|
|
|
SCMutexUnlock(&q->mutex_q);
|
|
|
|
SCMutexUnlock(&q->mutex_q);
|
|
|
|
return p;
|
|
|
|
return pq;
|
|
|
|
} else {
|
|
|
|
|
|
|
|
/* return NULL if we have no pkt. Should only happen on signals. */
|
|
|
|
|
|
|
|
SCMutexUnlock(&q->mutex_q);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int StoreQueueId(TmqhFlowCtx *ctx, char *name)
|
|
|
|
static int StoreQueueId(TmqhFlowCtx *ctx, char *name)
|
|
|
|
@ -147,6 +153,7 @@ static int StoreQueueId(TmqhFlowCtx *ctx, char *name)
|
|
|
|
memset(ctx->queues + (ctx->size - 1), 0, sizeof(TmqhFlowMode));
|
|
|
|
memset(ctx->queues + (ctx->size - 1), 0, sizeof(TmqhFlowMode));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ctx->queues[ctx->size - 1].q = tmq->pq;
|
|
|
|
ctx->queues[ctx->size - 1].q = tmq->pq;
|
|
|
|
|
|
|
|
SCLogNotice("size %d, mem %u", ctx->size, (uint32_t)(ctx->size * sizeof(TmqhFlowMode)));
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -171,6 +178,8 @@ void *TmqhOutputFlowSetupCtx(const char *queue_str)
|
|
|
|
TmqhFlowCtx *ctx = SCCalloc(1, sizeof(TmqhFlowCtx));
|
|
|
|
TmqhFlowCtx *ctx = SCCalloc(1, sizeof(TmqhFlowCtx));
|
|
|
|
if (unlikely(ctx == NULL))
|
|
|
|
if (unlikely(ctx == NULL))
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
SCLogNotice("ctx %p", ctx);
|
|
|
|
|
|
|
|
ctx->last_flow_qid = 0xffff;
|
|
|
|
|
|
|
|
|
|
|
|
char *str = SCStrdup(queue_str);
|
|
|
|
char *str = SCStrdup(queue_str);
|
|
|
|
if (unlikely(str == NULL)) {
|
|
|
|
if (unlikely(str == NULL)) {
|
|
|
|
@ -180,16 +189,16 @@ void *TmqhOutputFlowSetupCtx(const char *queue_str)
|
|
|
|
|
|
|
|
|
|
|
|
/* parse the comma separated string */
|
|
|
|
/* parse the comma separated string */
|
|
|
|
do {
|
|
|
|
do {
|
|
|
|
char *comma = strchr(tstr,',');
|
|
|
|
char *comma = strchr(tstr, ',');
|
|
|
|
if (comma != NULL) {
|
|
|
|
if (comma != NULL) {
|
|
|
|
*comma = '\0';
|
|
|
|
*comma = '\0';
|
|
|
|
char *qname = tstr;
|
|
|
|
char *qname = tstr;
|
|
|
|
int r = StoreQueueId(ctx,qname);
|
|
|
|
int r = StoreQueueId(ctx, qname);
|
|
|
|
if (r < 0)
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
char *qname = tstr;
|
|
|
|
char *qname = tstr;
|
|
|
|
int r = StoreQueueId(ctx,qname);
|
|
|
|
int r = StoreQueueId(ctx, qname);
|
|
|
|
if (r < 0)
|
|
|
|
if (r < 0)
|
|
|
|
goto error;
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@ -210,20 +219,61 @@ void TmqhOutputFlowFreeCtx(void *ctx)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx;
|
|
|
|
TmqhFlowCtx *fctx = (TmqhFlowCtx *)ctx;
|
|
|
|
|
|
|
|
|
|
|
|
SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16,
|
|
|
|
SCLogPerf("AutoFP - Total flow handler queues - %" PRIu16, fctx->size);
|
|
|
|
fctx->size);
|
|
|
|
|
|
|
|
SCFree(fctx->queues);
|
|
|
|
SCFree(fctx->queues);
|
|
|
|
SCFree(fctx);
|
|
|
|
SCFree(fctx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void Flush(ThreadVars *tv, TmqhFlowCtx *ctx, const uint32_t new_qid)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
SCLogDebug("flushing %p with new_qid %x last_flow_hash_cnt %u last_flow_qid %x", ctx, new_qid,
|
|
|
|
|
|
|
|
ctx->last_flow_hash_cnt, ctx->last_flow_qid);
|
|
|
|
|
|
|
|
const uint32_t old_qid = ctx->last_flow_qid;
|
|
|
|
|
|
|
|
ctx->last_flow_qid = new_qid;
|
|
|
|
|
|
|
|
ctx->last_flow_hash_cnt = 1;
|
|
|
|
|
|
|
|
const uint32_t qid = old_qid;
|
|
|
|
|
|
|
|
if (qid < ctx->size) {
|
|
|
|
|
|
|
|
SCLogDebug("flushing %p qid %x", ctx, qid);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
PacketQueue *q = ctx->queues[qid].q;
|
|
|
|
|
|
|
|
SCMutexLock(&q->mutex_q);
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
Packet *p = PacketDequeueNoLock(&ctx->last_flow_hash_queue);
|
|
|
|
|
|
|
|
PacketEnqueue(q, p);
|
|
|
|
|
|
|
|
} while (ctx->last_flow_hash_queue.len > 0);
|
|
|
|
|
|
|
|
SCCondSignal(&q->cond_q);
|
|
|
|
|
|
|
|
SCMutexUnlock(&q->mutex_q);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void TmqhOutputFlush(ThreadVars *tv)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Flush(tv, ctx, 0xffff);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void TmqhOutputFlowHash(ThreadVars *tv, Packet *p)
|
|
|
|
void TmqhOutputFlowHash(ThreadVars *tv, Packet *p)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
uint32_t qid;
|
|
|
|
uint32_t qid;
|
|
|
|
TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx;
|
|
|
|
TmqhFlowCtx *ctx = (TmqhFlowCtx *)tv->outctx;
|
|
|
|
|
|
|
|
|
|
|
|
if (p->flags & PKT_WANTS_FLOW) {
|
|
|
|
if (p->flags & PKT_WANTS_FLOW) {
|
|
|
|
uint32_t hash = p->flow_hash;
|
|
|
|
const uint32_t hash = p->flow_hash;
|
|
|
|
qid = hash % ctx->size;
|
|
|
|
qid = hash % ctx->size;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (qid != ctx->last_flow_qid || ctx->last_flow_hash_cnt == g_sync_pkts) {
|
|
|
|
|
|
|
|
Flush(tv, ctx, qid);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
ctx->last_flow_hash_cnt++;
|
|
|
|
|
|
|
|
if (ctx->last_flow_hash_cnt_max < ctx->last_flow_hash_cnt) {
|
|
|
|
|
|
|
|
ctx->last_flow_hash_cnt_max = ctx->last_flow_hash_cnt;
|
|
|
|
|
|
|
|
SCLogNotice("max same hash cnt %u", ctx->last_flow_hash_cnt_max);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
PacketEnqueueNoLock(&ctx->last_flow_hash_queue, p);
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
qid = ctx->last++;
|
|
|
|
qid = ctx->last++;
|
|
|
|
|
|
|
|
|
|
|
|
@ -390,16 +440,12 @@ static int TmqhOutputFlowSetupCtxTest03(void)
|
|
|
|
PASS;
|
|
|
|
PASS;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void TmqhFlowRegisterTests(void)
|
|
|
|
void TmqhFlowRegisterTests(void)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
#ifdef UNITTESTS
|
|
|
|
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest01",
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest01",
|
|
|
|
TmqhOutputFlowSetupCtxTest01);
|
|
|
|
TmqhOutputFlowSetupCtxTest01);
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest02",
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest02",
|
|
|
|
TmqhOutputFlowSetupCtxTest02);
|
|
|
|
TmqhOutputFlowSetupCtxTest02);
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest03",
|
|
|
|
UtRegisterTest("TmqhOutputFlowSetupCtxTest03", TmqhOutputFlowSetupCtxTest03);
|
|
|
|
TmqhOutputFlowSetupCtxTest03);
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* UNITTESTS */
|
|
|
|
|