66 static void ThresholdCacheInit(
void);
74 static int g_threshold_force_alloc_fail = 0;
78 g_threshold_force_alloc_fail = v;
93 #define DF_PORT_BITMAP_SIZE (65536u / 8u)
94 #define DF_PORT_BYTE_IDX(p) ((uint32_t)((p) >> 3))
95 #define DF_PORT_BIT_MASK(p) ((uint8_t)(1u << ((p)&7u)))
101 static int ThresholdsInit(
struct Thresholds *t);
102 static void ThresholdsDestroy(
struct Thresholds *t);
104 static uint64_t ThresholdBitmapAllocFailCounter(
void)
109 static uint64_t ThresholdBitmapMemuseCounter(
void)
114 static uint64_t ThresholdCacheMemuseCounter(
void)
119 static uint64_t ThresholdMemuseCounter(
void)
126 static uint64_t ThresholdMemcapCounter(
void)
139 if (ThresholdsInit(&
ctx) < 0) {
140 FatalError(
"Failed to initialize threshold table");
142 ThresholdCacheInit();
152 "detect.thresholds.bitmap_alloc_fail", ThresholdBitmapAllocFailCounter);
157 ThresholdsDestroy(&
ctx);
189 static int ThresholdEntrySet(
void *
dst,
void *
src)
193 memset(edst, 0,
sizeof(*edst));
208 if (g_threshold_force_alloc_fail) {
245 static inline void ThresholdDistinctAddPort(
ThresholdEntry *te, uint16_t port)
259 static void ThresholdEntryFree(
void *ptr)
277 static inline uint32_t HashAddress(
const Address *a,
const uint32_t seed)
281 if (a->
family == AF_INET) {
282 key =
hashword(a->addr_data32, 1, seed);
283 }
else if (a->
family == AF_INET6) {
284 key =
hashword(a->addr_data32, 4, seed);
291 static inline int CompareAddress(
const Address *a,
const Address *b)
296 return (a->addr_data32[0] == b->addr_data32[0]);
304 static uint32_t ThresholdEntryHash(
const uint32_t seed,
void *ptr)
307 uint32_t hash =
hashword(e->
key,
sizeof(e->
key) /
sizeof(uint32_t), seed);
310 hash += HashAddress(&e->
addr2, seed);
314 hash += HashAddress(&e->
addr, seed);
320 static bool ThresholdEntryCompare(
void *a,
void *b)
326 if (memcmp(e1->
key, e2->
key,
sizeof(e1->
key)) != 0)
330 if (!(CompareAddress(&e1->
addr2, &e2->
addr2)))
335 if (!(CompareAddress(&e1->
addr, &e2->
addr)))
342 static bool ThresholdEntryExpire(
void *data,
const SCTime_t ts)
349 static int ThresholdsInit(
struct Thresholds *t)
352 uint64_t memcap = 16 * 1024 * 1024;
357 SCLogError(
"Error parsing detect.thresholds.memcap from conf file - %s",
str);
363 if ((
SCConfGetInt(
"detect.thresholds.hash-size", &value)) == 1) {
364 if (value < 256 || value > INT_MAX) {
365 SCLogError(
"'detect.thresholds.hash-size' value %" PRIiMAX
366 " out of range. Valid range 256-2147483647.",
374 ThresholdEntryFree, ThresholdEntryHash, ThresholdEntryCompare, ThresholdEntryExpire,
376 if (t->
thash == NULL) {
377 SCLogError(
"failed to initialize thresholds hash table");
383 static void ThresholdsDestroy(
struct Thresholds *t)
427 struct THRESHOLD_CACHE
tree;
443 #define THRESHOLD_CACHE_MAX_ENTRIES_DEFAULT 256
444 #define THRESHOLD_CACHE_MAX_ENTRIES_MIN 256
445 #define THRESHOLD_CACHE_MAX_ENTRIES_MAX 1048576
450 #define THRESHOLD_CACHE_ENTRY_MEM (sizeof(ThresholdCacheItem) + sizeof(HashTableBucket))
456 SCLogPerf(
"threshold thread cache stats: cnt:%" PRIu64
" nosupport:%" PRIu64
457 " miss_expired:%" PRIu64
" miss:%" PRIu64
" hit:%" PRIu64
", entries:%" PRIu32
458 ", housekeeping: checks:%" PRIu64
", expired:%" PRIu64,
465 if (
unlikely(det_ctx->
tv == NULL || thread_storage_id.
id < 0)) {
484 THRESHOLD_CACHE_RB_REMOVE(&tctx->
tree, iter);
499 static uint32_t ThresholdCacheHashFunc(
HashTable *
ht,
void *data, uint16_t datalen)
508 static char ThresholdCacheHashCompareFunc(
509 void *data1, uint16_t datalen1,
void *data2, uint16_t datalen2)
514 memcmp(tci1->
key, tci2->
key,
sizeof(tci1->
key)) == 0;
517 static void ThresholdCacheHashFreeFunc(
void *data)
524 const int8_t retval,
const uint32_t sid,
const uint32_t gid,
const uint32_t rev,
534 addr =
p->
src.addr_data32[0];
536 addr =
p->
dst.addr_data32[0];
550 .expires_at = expires,
557 if (tctx->
entries >= cache_max_entries) {
559 if (victim == NULL) {
564 THRESHOLD_CACHE_RB_REMOVE(&tctx->
tree, victim);
597 THRESHOLD_CACHE_RB_REMOVE(&tctx->
tree, found);
598 THRESHOLD_CACHE_RB_INSERT(&tctx->
tree, found);
612 const uint32_t sid,
const uint32_t gid,
const uint32_t rev)
623 addr =
p->
src.addr_data32[0];
625 addr =
p->
dst.addr_data32[0];
632 ThresholdCacheExpire(det_ctx,
p->
ts);
647 THRESHOLD_CACHE_RB_REMOVE(&tctx->
tree, found);
661 static void ThresholdCacheThreadFree(
void *ptr)
665 DumpCacheStats(tctx);
673 static void ThresholdCacheInit(
void)
680 if (
SCConfGetInt(
"detect.thresholds.cache.max-entries", &value) == 1) {
683 SCLogError(
"'detect.thresholds.cache.max-entries' value %" PRIdMAX
684 " out of range. Valid range %d-%d.",
686 FatalError(
"Invalid value for detect.thresholds.cache.max-entries");
688 cache_max_entries = (uint32_t)value;
693 if (thread_storage_id.
id < 0) {
694 FatalError(
"Failed to register threshold_cache thread storage");
703 if (thread_storage_id.
id < 0)
715 uint32_t
hashsize = cache_max_entries;
717 uint32_t hashpow = 1;
722 ThresholdCacheHashFreeFunc, seed);
723 if (tctx->
ht == NULL) {
735 sizeof(*tctx) +
sizeof(*tctx->
ht) + (uint64_t)hashpow *
sizeof(
HashTableBucket *);
831 Flow *
f, uint32_t sid, uint32_t gid, uint32_t rev, uint32_t tenant_id)
838 if (e->threshold.
key[
SID] == sid && e->threshold.
key[
GID] == gid &&
839 e->threshold.
key[
REV] == rev && e->threshold.
key[
TENANT] == tenant_id) {
840 return &e->threshold;
865 static int ThresholdHandlePacketSuppress(
901 static inline void RateFilterSetAction(
PacketAlert *pa, uint8_t new_action)
903 switch (new_action) {
930 static uint32_t BackoffCalcNextValue(
const uint32_t cur,
const uint32_t
m)
945 const uint32_t sid,
const uint32_t gid,
const uint32_t rev)
963 ThresholdDistinctInit(te, td);
970 ThresholdDistinctAddPort(te, port);
990 if (td->
count == 1) {
1005 const uint32_t sid,
const uint32_t gid,
const uint32_t rev,
PacketAlert *pa)
1022 if (PacketIsIPv4(
p)) {
1023 SetupCache(det_ctx,
p, td->
track, (int8_t)ret, sid, gid, rev, entry);
1057 if (PacketIsIPv4(
p)) {
1058 SetupCache(det_ctx,
p, td->
track, (int8_t)ret, sid, gid, rev, entry);
1079 ThresholdDistinctAddPort(te, port);
1092 ThresholdDistinctReset(te);
1097 ThresholdDistinctAddPort(te, port);
1106 const uint8_t original_action = pa->
action;
1129 te->
tv1 = packet_time;
1136 if (pa->
action == original_action) {
1175 memset(&lookup, 0,
sizeof(lookup));
1187 if (PacketIsIPv4(
p)) {
1213 r = ThresholdSetup(td, te,
p, s->
id, s->
gid, s->
rev);
1216 r = ThresholdCheckUpdate(
de_ctx, det_ctx, td, te,
p, s->
id, s->
gid, s->
rev, pa);
1220 THashDataUnlock(res.
data);
1237 SCLogDebug(
"found %p sid %u gid %u rev %u", found, sid, gid, rev);
1239 if (found == NULL) {
1245 ret = ThresholdSetup(td, &new->threshold,
p, sid, gid, rev);
1247 if (AddEntryToFlow(
f,
new,
p->
ts) == -1) {
1253 ret = ThresholdCheckUpdate(
de_ctx, det_ctx, td, found,
p, sid, gid, rev, pa);
1281 ret = ThresholdHandlePacketSuppress(
p, td, s->
id, s->
gid);
1284 int cache_ret = CheckCache(det_ctx,
p, td->
track, s->
id, s->
gid, s->
rev);
1285 if (cache_ret >= 0) {
1290 ret = ThresholdGetFromHash(
de_ctx, det_ctx, &
ctx,
p, s, td, pa);
1293 int cache_ret = CheckCache(det_ctx,
p, td->
track, s->
id, s->
gid, s->
rev);
1294 if (cache_ret >= 0) {
1299 ret = ThresholdGetFromHash(
de_ctx, det_ctx, &
ctx,
p, s, td, pa);
1301 ret = ThresholdGetFromHash(
de_ctx, det_ctx, &
ctx,
p, s, td, pa);
1303 ret = ThresholdGetFromHash(
de_ctx, det_ctx, &
ctx,
p, s, td, pa);
1306 ret = ThresholdHandlePacketFlow(