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