suricata
defrag-hash.c
Go to the documentation of this file.
1/* Copyright (C) 2007-2024 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18#include "suricata-common.h"
19#include "conf.h"
20#include "defrag-hash.h"
21#include "defrag-stack.h"
22#include "defrag-config.h"
23#include "defrag-timeout.h"
24#include "util-random.h"
25#include "util-byte.h"
26#include "util-misc.h"
27#include "util-hash-lookup3.h"
28#include "util-validate.h"
29
30/** defrag tracker hash table */
33SC_ATOMIC_DECLARE(uint64_t,defrag_memuse);
34SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter);
35SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx);
36
37static DefragTracker *DefragTrackerGetUsedDefragTracker(
39
40/** queue with spare tracker */
41static DefragTrackerStack defragtracker_spare_q;
42
43/**
44 * \brief Update memcap value
45 *
46 * \param size new memcap value
47 */
48int DefragTrackerSetMemcap(uint64_t size)
49{
50 if ((uint64_t)SC_ATOMIC_GET(defrag_memuse) < size) {
51 SC_ATOMIC_SET(defrag_config.memcap, size);
52 return 1;
53 }
54
55 return 0;
56}
57
58/**
59 * \brief Return memcap value
60 *
61 * \retval memcap value
62 */
64{
65 uint64_t memcapcopy = SC_ATOMIC_GET(defrag_config.memcap);
66 return memcapcopy;
67}
68
69/**
70 * \brief Return memuse value
71 *
72 * \retval memuse value
73 */
75{
76 uint64_t memusecopy = (uint64_t)SC_ATOMIC_GET(defrag_memuse);
77 return memusecopy;
78}
79
84
86{
87 DefragTrackerEnqueue(&defragtracker_spare_q, h);
88 (void) SC_ATOMIC_SUB(defragtracker_counter, 1);
89}
90
91static DefragTracker *DefragTrackerAlloc(void)
92{
93 if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
94 return NULL;
95 }
96
97 (void) SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker));
98
99 DefragTracker *dt = SCCalloc(1, sizeof(DefragTracker));
100 if (unlikely(dt == NULL))
101 goto error;
102
103 SCMutexInit(&dt->lock, NULL);
104 SC_ATOMIC_INIT(dt->use_cnt);
105 return dt;
106
107error:
108 return NULL;
109}
110
111static void DefragTrackerFree(DefragTracker *dt)
112{
113 if (dt != NULL) {
115
116 SCMutexDestroy(&dt->lock);
117 SCFree(dt);
118 (void) SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker));
119 }
120}
121
122#define DefragTrackerIncrUsecnt(dt) \
123 SC_ATOMIC_ADD((dt)->use_cnt, 1)
124#define DefragTrackerDecrUsecnt(dt) \
125 SC_ATOMIC_SUB((dt)->use_cnt, 1)
126
127static void DefragTrackerInit(DefragTracker *dt, Packet *p)
128{
129 /* copy address */
130 COPY_ADDRESS(&p->src, &dt->src_addr);
131 COPY_ADDRESS(&p->dst, &dt->dst_addr);
132
133 if (PacketIsIPv4(p)) {
134 const IPV4Hdr *ip4h = PacketGetIPv4(p);
135 dt->id = (int32_t)IPV4_GET_RAW_IPID(ip4h);
136 dt->af = AF_INET;
137 } else {
138 DEBUG_VALIDATE_BUG_ON(!PacketIsIPv6(p));
139 dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p);
140 dt->af = AF_INET6;
141 }
142 dt->proto = PacketGetIPProto(p);
143 memcpy(&dt->vlan_id[0], &p->vlan_id[0], sizeof(dt->vlan_id));
144 dt->policy = DefragGetOsPolicy(p);
146 dt->remove = 0;
147 dt->seen_last = 0;
148
149 (void) DefragTrackerIncrUsecnt(dt);
150}
151
157
162
163#define DEFRAG_DEFAULT_HASHSIZE 4096
164#define DEFRAG_DEFAULT_MEMCAP 16777216
165#define DEFRAG_DEFAULT_PREALLOC 1000
166
167/** \brief initialize the configuration
168 * \warning Not thread safe */
169void DefragInitConfig(bool quiet)
170{
171 SCLogDebug("initializing defrag engine...");
172
173 memset(&defrag_config, 0, sizeof(defrag_config));
174 SC_ATOMIC_INIT(defragtracker_counter);
175 SC_ATOMIC_INIT(defrag_memuse);
176 SC_ATOMIC_INIT(defragtracker_prune_idx);
178 DefragTrackerStackInit(&defragtracker_spare_q);
179
180 /* set defaults */
181 defrag_config.hash_rand = (uint32_t)RandomGet();
185 defrag_config.memcap_policy = ExceptionPolicyParse("defrag.memcap-policy", false);
186
187 /* Check if we have memcap and hash_size defined at config */
188 const char *conf_val;
189 uint32_t configval = 0;
190
191 uint64_t defrag_memcap;
192 /** set config values for memcap, prealloc and hash_size */
193 if ((SCConfGet("defrag.memcap", &conf_val)) == 1) {
194 if (ParseSizeStringU64(conf_val, &defrag_memcap) < 0) {
195 SCLogError("Error parsing defrag.memcap "
196 "from conf file - %s. Killing engine",
197 conf_val);
198 exit(EXIT_FAILURE);
199 } else {
200 SC_ATOMIC_SET(defrag_config.memcap, defrag_memcap);
201 }
202 }
203 if ((SCConfGet("defrag.hash-size", &conf_val)) == 1) {
204 if (StringParseUint32(&configval, 10, strlen(conf_val),
205 conf_val) > 0) {
206 defrag_config.hash_size = configval;
207 } else {
208 WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size);
209 }
210 }
211
212 if ((SCConfGet("defrag.trackers", &conf_val)) == 1) {
213 if (StringParseUint32(&configval, 10, strlen(conf_val),
214 conf_val) > 0) {
215 defrag_config.prealloc = configval;
216 } else {
217 WarnInvalidConfEntry("defrag.trackers", "%"PRIu32, defrag_config.prealloc);
218 }
219 }
220 SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: "
221 "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(defrag_config.memcap),
223
224 /* alloc hash memory */
225 uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow);
226 if (!(DEFRAG_CHECK_MEMCAP(hash_size))) {
227 SCLogError("allocating defrag hash failed: "
228 "max defrag memcap is smaller than projected hash size. "
229 "Memcap: %" PRIu64 ", Hash table size %" PRIu64 ". Calculate "
230 "total hash size by multiplying \"defrag.hash-size\" with %" PRIuMAX ", "
231 "which is the hash bucket size.",
232 SC_ATOMIC_GET(defrag_config.memcap), hash_size,
233 (uintmax_t)sizeof(DefragTrackerHashRow));
234 exit(EXIT_FAILURE);
235 }
237 if (unlikely(defragtracker_hash == NULL)) {
238 FatalError("Fatal error encountered in DefragTrackerInitConfig. Exiting...");
239 }
241
242 uint32_t i = 0;
243 for (i = 0; i < defrag_config.hash_size; i++) {
245 }
246 (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow)));
247
248 if (!quiet) {
249 SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... "
250 "%" PRIu32 " buckets of size %" PRIuMAX "",
251 SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size,
252 (uintmax_t)sizeof(DefragTrackerHashRow));
253 }
254
255 if ((SCConfGet("defrag.prealloc", &conf_val)) == 1) {
256 if (SCConfValIsTrue(conf_val)) {
257 /* pre allocate defrag trackers */
258 for (i = 0; i < defrag_config.prealloc; i++) {
259 if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
260 SCLogError("preallocating defrag trackers failed: "
261 "max defrag memcap reached. Memcap %" PRIu64 ", "
262 "Memuse %" PRIu64 ".",
264 ((uint64_t)SC_ATOMIC_GET(defrag_memuse) +
265 (uint64_t)sizeof(DefragTracker)));
266 exit(EXIT_FAILURE);
267 }
268
269 DefragTracker *h = DefragTrackerAlloc();
270 if (h == NULL) {
271 SCLogError("preallocating defrag failed: %s", strerror(errno));
272 exit(EXIT_FAILURE);
273 }
274 DefragTrackerEnqueue(&defragtracker_spare_q,h);
275 }
276 if (!quiet) {
277 SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "",
278 DefragTrackerStackSize(&defragtracker_spare_q),
279 (uintmax_t)sizeof(DefragTracker));
280 }
281 }
282 }
283
284 if (!quiet) {
285 SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
286 SC_ATOMIC_GET(defrag_memuse), SC_ATOMIC_GET(defrag_config.memcap));
287 }
288}
289
290/** \brief shutdown the flow engine
291 * \warning Not thread safe */
293{
294 DefragTracker *dt;
295
296 /* free spare queue */
297 while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) {
298 BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0);
299 DefragTrackerFree(dt);
300 }
301
302 /* clear and free the hash */
303 if (defragtracker_hash != NULL) {
304 for (uint32_t u = 0; u < defrag_config.hash_size; u++) {
305 dt = defragtracker_hash[u].head;
306 while (dt) {
307 DefragTracker *n = dt->hnext;
309 DefragTrackerFree(dt);
310 dt = n;
311 }
312
314 }
316 defragtracker_hash = NULL;
317 }
318 (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow));
319 DefragTrackerStackDestroy(&defragtracker_spare_q);
320}
321
322/** \brief compare two raw ipv6 addrs
323 *
324 * \note we don't care about the real ipv6 ip's, this is just
325 * to consistently fill the DefragHashKey6 struct, without all
326 * the SCNtohl calls.
327 *
328 * \warning do not use elsewhere unless you know what you're doing.
329 * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
330 * what you are looking for.
331 */
332static inline int DefragHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
333{
334 for (int i = 0; i < 4; i++) {
335 if (a[i] > b[i])
336 return 1;
337 if (a[i] < b[i])
338 break;
339 }
340
341 return 0;
342}
343
344typedef struct DefragHashKey4_ {
345 union {
346 struct {
347 uint32_t src, dst;
348 uint32_t id;
350 uint16_t pad[1];
351 };
352 uint32_t u32[5];
353 };
355
356typedef struct DefragHashKey6_ {
357 union {
358 struct {
359 uint32_t src[4], dst[4];
360 uint32_t id;
362 uint16_t pad[1];
363 };
364 uint32_t u32[11];
365 };
367
368/* calculate the hash key for this packet
369 *
370 * we're using:
371 * hash_rand -- set at init time
372 * source address
373 * destination address
374 * id
375 * vlan_id
376 */
377static inline uint32_t DefragHashGetKey(Packet *p)
378{
379 uint32_t key;
380
381 if (PacketIsIPv4(p)) {
382 const IPV4Hdr *ip4h = PacketGetIPv4(p);
383 DefragHashKey4 dhk = { .pad[0] = 0 };
384 if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
385 dhk.src = p->src.addr_data32[0];
386 dhk.dst = p->dst.addr_data32[0];
387 } else {
388 dhk.src = p->dst.addr_data32[0];
389 dhk.dst = p->src.addr_data32[0];
390 }
391 dhk.id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
392 memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
393
394 uint32_t hash =
395 hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
396 key = hash % defrag_config.hash_size;
397 } else if (PacketIsIPv6(p)) {
398 DefragHashKey6 dhk = { .pad[0] = 0 };
399 if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
400 dhk.src[0] = p->src.addr_data32[0];
401 dhk.src[1] = p->src.addr_data32[1];
402 dhk.src[2] = p->src.addr_data32[2];
403 dhk.src[3] = p->src.addr_data32[3];
404 dhk.dst[0] = p->dst.addr_data32[0];
405 dhk.dst[1] = p->dst.addr_data32[1];
406 dhk.dst[2] = p->dst.addr_data32[2];
407 dhk.dst[3] = p->dst.addr_data32[3];
408 } else {
409 dhk.src[0] = p->dst.addr_data32[0];
410 dhk.src[1] = p->dst.addr_data32[1];
411 dhk.src[2] = p->dst.addr_data32[2];
412 dhk.src[3] = p->dst.addr_data32[3];
413 dhk.dst[0] = p->src.addr_data32[0];
414 dhk.dst[1] = p->src.addr_data32[1];
415 dhk.dst[2] = p->src.addr_data32[2];
416 dhk.dst[3] = p->src.addr_data32[3];
417 }
418 dhk.id = IPV6_EXTHDR_GET_FH_ID(p);
419 memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
420
421 uint32_t hash =
422 hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
423 key = hash % defrag_config.hash_size;
424 } else {
425 key = 0;
426 }
427 return key;
428}
429
430/* Since two or more trackers can have the same hash key, we need to compare
431 * the tracker with the current tracker key. */
432#define CMP_DEFRAGTRACKER(d1, d2, id) \
433 (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
434 (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
435 (d1)->proto == PacketGetIPProto(d2) && (d1)->id == (id) && \
436 (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \
437 (d1)->vlan_id[2] == (d2)->vlan_id[2])
438
439static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
440{
441 uint32_t id;
442 if (PacketIsIPv4(p)) {
443 const IPV4Hdr *ip4h = PacketGetIPv4(p);
444 id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
445 } else {
446 id = IPV6_EXTHDR_GET_FH_ID(p);
447 }
448
449 return CMP_DEFRAGTRACKER(t, p, id);
450}
451
452static void DefragExceptionPolicyStatsIncr(
454{
455 uint16_t id = dtv->counter_defrag_memcap_eps.eps_id[policy];
456 if (likely(id > 0)) {
457 StatsIncr(tv, id);
458 }
459}
460
461/**
462 * \brief Get a new defrag tracker
463 *
464 * Get a new defrag tracker. We're checking memcap first and will try to make room
465 * if the memcap is reached.
466 *
467 * \retval dt *LOCKED* tracker on success, NULL on error.
468 */
469static DefragTracker *DefragTrackerGetNew(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
470{
471#ifdef DEBUG
472 if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == p->pcap_cnt) {
473 SCLogNotice("simulating memcap hit for packet %" PRIu64, p->pcap_cnt);
475 DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
476 return NULL;
477 }
478#endif
479
480 DefragTracker *dt = NULL;
481
482 /* get a tracker from the spare queue */
483 dt = DefragTrackerDequeue(&defragtracker_spare_q);
484 if (dt == NULL) {
485 /* If we reached the max memcap, we get a used tracker */
486 if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
487 dt = DefragTrackerGetUsedDefragTracker(tv, dtv);
488 if (dt == NULL) {
490 DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
491 return NULL;
492 }
493
494 /* freed a tracker, but it's unlocked */
495 } else {
496 /* now see if we can alloc a new tracker */
497 dt = DefragTrackerAlloc();
498 if (dt == NULL) {
500 DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
501 return NULL;
502 }
503
504 /* tracker is initialized but *unlocked* */
505 }
506 } else {
507 /* tracker has been recycled before it went into the spare queue */
508
509 /* tracker is initialized (recycled) but *unlocked* */
510 }
511
512 (void) SC_ATOMIC_ADD(defragtracker_counter, 1);
513 SCMutexLock(&dt->lock);
514 return dt;
515}
516
517/* DefragGetTrackerFromHash
518 *
519 * Hash retrieval function for trackers. Looks up the hash bucket containing the
520 * tracker pointer. Then compares the packet with the found tracker to see if it is
521 * the tracker we need. If it isn't, walk the list until the right tracker is found.
522 *
523 * returns a *LOCKED* tracker or NULL
524 */
526{
527 DefragTracker *dt = NULL;
528
529 /* get the key to our bucket */
530 uint32_t key = DefragHashGetKey(p);
531 /* get our hash bucket and lock it */
533 DRLOCK_LOCK(hb);
534
535 /* see if the bucket already has a tracker */
536 if (hb->head == NULL) {
537 dt = DefragTrackerGetNew(tv, dtv, p);
538 if (dt == NULL) {
539 DRLOCK_UNLOCK(hb);
540 return NULL;
541 }
542
543 /* tracker is locked */
544 hb->head = dt;
545
546 /* got one, now lock, initialize and return */
547 DefragTrackerInit(dt,p);
548
549 DRLOCK_UNLOCK(hb);
550 return dt;
551 }
552
553 /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
554 DefragTracker *prev_dt = NULL;
555 dt = hb->head;
556
557 do {
558 DefragTracker *next_dt = NULL;
559
560 SCMutexLock(&dt->lock);
561 if (DefragTrackerTimedOut(dt, p->ts)) {
562 next_dt = dt->hnext;
563 dt->hnext = NULL;
564 if (prev_dt) {
565 prev_dt->hnext = next_dt;
566 } else {
567 hb->head = next_dt;
568 }
570 SCMutexUnlock(&dt->lock);
571
574 goto tracker_removed;
575 } else if (!dt->remove && DefragTrackerCompare(dt, p)) {
576 /* found our tracker, keep locked & return */
577 (void)DefragTrackerIncrUsecnt(dt);
578 DRLOCK_UNLOCK(hb);
579 return dt;
580 }
581 SCMutexUnlock(&dt->lock);
582 /* unless we removed 'dt', prev_dt needs to point to
583 * current 'dt' when adding a new tracker below. */
584 prev_dt = dt;
585 next_dt = dt->hnext;
586
587 tracker_removed:
588 if (next_dt == NULL) {
589 dt = DefragTrackerGetNew(tv, dtv, p);
590 if (dt == NULL) {
591 DRLOCK_UNLOCK(hb);
592 return NULL;
593 }
594 dt->hnext = hb->head;
595 hb->head = dt;
596
597 /* tracker is locked */
598
599 /* initialize and return */
600 DefragTrackerInit(dt, p);
601
602 DRLOCK_UNLOCK(hb);
603 return dt;
604 }
605
606 dt = next_dt;
607 } while (dt != NULL);
608
609 /* should be unreachable */
610 BUG_ON(1);
611 return NULL;
612}
613
614/** \brief look up a tracker in the hash
615 *
616 * \param a address to look up
617 *
618 * \retval h *LOCKED* tracker or NULL
619 */
621{
622 DefragTracker *dt = NULL;
623
624 /* get the key to our bucket */
625 uint32_t key = DefragHashGetKey(p);
626 /* get our hash bucket and lock it */
628 DRLOCK_LOCK(hb);
629
630 /* see if the bucket already has a tracker */
631 if (hb->head == NULL) {
632 DRLOCK_UNLOCK(hb);
633 return dt;
634 }
635
636 /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
637 dt = hb->head;
638
639 do {
640 if (!dt->remove && DefragTrackerCompare(dt, p)) {
641 /* found our tracker, lock & return */
642 SCMutexLock(&dt->lock);
643 (void)DefragTrackerIncrUsecnt(dt);
644 DRLOCK_UNLOCK(hb);
645 return dt;
646
647 } else if (dt->hnext == NULL) {
648 DRLOCK_UNLOCK(hb);
649 return NULL;
650 }
651
652 dt = dt->hnext;
653 } while (dt != NULL);
654
655 /* should be unreachable */
656 BUG_ON(1);
657 return NULL;
658}
659
660/** \internal
661 * \brief Get a tracker from the hash directly.
662 *
663 * Called in conditions where the spare queue is empty and memcap is reached.
664 *
665 * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes
666 * sure we don't start at the top each time since that would clear the top of
667 * the hash leading to longer and longer search times under high pressure (observed).
668 *
669 * \retval dt tracker or NULL
670 */
671static DefragTracker *DefragTrackerGetUsedDefragTracker(ThreadVars *tv, const DecodeThreadVars *dtv)
672{
673 uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size;
674 uint32_t cnt = defrag_config.hash_size;
675
676 while (cnt--) {
677 if (++idx >= defrag_config.hash_size)
678 idx = 0;
679
681
682 if (DRLOCK_TRYLOCK(hb) != 0)
683 continue;
684
685 DefragTracker *dt = hb->head;
686 if (dt == NULL) {
687 DRLOCK_UNLOCK(hb);
688 continue;
689 }
690
691 if (SCMutexTrylock(&dt->lock) != 0) {
692 DRLOCK_UNLOCK(hb);
693 continue;
694 }
695
696 /** never prune a tracker that is used by a packets
697 * we are currently processing in one of the threads */
698 if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
699 DRLOCK_UNLOCK(hb);
700 SCMutexUnlock(&dt->lock);
701 continue;
702 }
703
704 /* only count "forced" reuse */
705 bool incr_reuse_cnt = !dt->remove;
706
707 /* remove from the hash */
708 hb->head = dt->hnext;
709
710 dt->hnext = NULL;
711 DRLOCK_UNLOCK(hb);
712
714
715 SCMutexUnlock(&dt->lock);
716
717 if (incr_reuse_cnt) {
719 } else {
721 }
722
723 (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt));
724 return dt;
725 }
726
727 return NULL;
728}
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition conf.c:551
int SCConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition conf.c:350
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition counters.c:166
#define IPV4_GET_RAW_IPID(ip4h)
Definition decode-ipv4.h:99
#define IPV6_EXTHDR_GET_FH_ID(p)
#define VLAN_MAX_LAYERS
Definition decode-vlan.h:51
@ PKT_DROP_REASON_DEFRAG_MEMCAP
Definition decode.h:384
#define COPY_ADDRESS(a, b)
Definition decode.h:127
int DefragPolicyGetHostTimeout(Packet *p)
DefragConfig defrag_config
Definition defrag-hash.c:32
uint64_t DefragTrackerGetMemcap(void)
Return memcap value.
Definition defrag-hash.c:63
void DefragTrackerRelease(DefragTracker *t)
#define DEFRAG_DEFAULT_MEMCAP
#define DEFRAG_DEFAULT_PREALLOC
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition defrag-hash.c:74
enum ExceptionPolicy DefragGetMemcapExceptionPolicy(void)
Definition defrag-hash.c:80
struct DefragHashKey4_ DefragHashKey4
void DefragTrackerMoveToSpare(DefragTracker *h)
Definition defrag-hash.c:85
#define CMP_DEFRAGTRACKER(d1, d2, id)
#define DefragTrackerDecrUsecnt(dt)
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
void DefragTrackerClearMemory(DefragTracker *dt)
void DefragInitConfig(bool quiet)
initialize the configuration
DefragTrackerHashRow * defragtracker_hash
Definition defrag-hash.c:31
void DefragHashShutdown(void)
shutdown the flow engine
#define DefragTrackerIncrUsecnt(dt)
#define DEFRAG_DEFAULT_HASHSIZE
int DefragTrackerSetMemcap(uint64_t size)
Update memcap value.
Definition defrag-hash.c:48
struct DefragHashKey6_ DefragHashKey6
#define DRLOCK_INIT(fb)
Definition defrag-hash.h:51
#define DRLOCK_TRYLOCK(fb)
Definition defrag-hash.h:54
#define DEFRAG_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition defrag-hash.h:83
struct DefragTrackerHashRow_ DefragTrackerHashRow
#define DRLOCK_UNLOCK(fb)
Definition defrag-hash.h:55
#define DRLOCK_DESTROY(fb)
Definition defrag-hash.h:52
#define DRLOCK_LOCK(fb)
Definition defrag-hash.h:53
uint32_t DefragTrackerStackSize(DefragTrackerStack *q)
return stack size
DefragTracker * DefragTrackerDequeue(DefragTrackerStack *q)
remove a tracker from the queue
DefragTrackerStack * DefragTrackerStackInit(DefragTrackerStack *q)
void DefragTrackerStackDestroy(DefragTrackerStack *q)
Destroy a tracker queue.
void DefragTrackerEnqueue(DefragTrackerStack *q, DefragTracker *dt)
add a tracker to a queue
int DefragTrackerTimedOut(DefragTracker *dt, SCTime_t ts)
uint8_t DefragGetOsPolicy(Packet *p)
Get the defrag policy based on the destination address of the packet.
Definition defrag.c:985
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition defrag.c:132
uint32_t id
DecodeThreadVars * dtv
ThreadVars * tv
Structure to hold thread specific data for all decode modules.
Definition decode.h:963
uint16_t counter_defrag_tracker_soft_reuse
Definition decode.h:1024
uint16_t counter_defrag_tracker_timeout
Definition decode.h:1026
ExceptionPolicyCounters counter_defrag_memcap_eps
Definition decode.h:1027
uint16_t counter_defrag_tracker_hard_reuse
Definition decode.h:1025
uint32_t prealloc
Definition defrag-hash.h:72
uint32_t hash_size
Definition defrag-hash.h:71
enum ExceptionPolicy memcap_policy
Definition defrag-hash.h:73
uint32_t hash_rand
Definition defrag-hash.h:70
uint32_t u32[5]
uint16_t pad[1]
uint16_t vlan_id[VLAN_MAX_LAYERS]
uint16_t vlan_id[VLAN_MAX_LAYERS]
uint16_t pad[1]
uint32_t dst[4]
uint32_t src[4]
uint32_t u32[11]
DefragTracker * head
Definition defrag-hash.h:62
uint8_t remove
Definition defrag.h:104
SCMutex lock
Definition defrag.h:85
uint8_t seen_last
Definition defrag.h:102
struct DefragTracker_ * hnext
Definition defrag.h:119
uint8_t policy
Definition defrag.h:97
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition defrag.h:88
uint32_t id
Definition defrag.h:92
Address src_addr
Definition defrag.h:106
Address dst_addr
Definition defrag.h:107
uint8_t af
Definition defrag.h:99
uint32_t host_timeout
Definition defrag.h:111
uint8_t proto
Definition defrag.h:95
uint16_t eps_id[EXCEPTION_POLICY_MAX]
uint64_t pcap_cnt
Definition decode.h:626
SCTime_t ts
Definition decode.h:555
Address src
Definition decode.h:505
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition decode.h:528
Address dst
Definition decode.h:506
Per thread variable structure.
Definition threadvars.h:58
#define BUG_ON(x)
#define SCMutexDestroy
#define SCMutexUnlock(mut)
#define SCMutexTrylock(mut)
#define SCMutexInit(mut, mutattrs)
#define SCMutexLock(mut)
uint32_t cnt
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
#define SC_ATOMIC_DECLARE(type, name)
wrapper for declaring atomic variables.
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition util-byte.c:313
#define FatalError(...)
Definition util-debug.h:510
#define SCLogDebug(...)
Definition util-debug.h:275
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition util-debug.h:243
#define SCLogError(...)
Macro used to log ERROR messages.
Definition util-debug.h:267
#define SCLogConfig(...)
Definition util-debug.h:229
enum ExceptionPolicy ExceptionPolicyParse(const char *option, bool support_flow)
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
#define SCFree(p)
Definition util-mem.h:61
#define SCCalloc(nm, sz)
Definition util-mem.h:53
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition util-misc.c:190
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition util-misc.h:35
#define likely(expr)
#define unlikely(expr)
long int RandomGet(void)
#define DEBUG_VALIDATE_BUG_ON(exp)