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 */
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  goto error;
102 
103  SCMutexInit(&dt->lock, NULL);
104  SC_ATOMIC_INIT(dt->use_cnt);
105  return dt;
106 
107 error:
108  return NULL;
109 }
110 
111 static 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 
127 static 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 
153 {
154  (void) DefragTrackerDecrUsecnt(t);
155  SCMutexUnlock(&t->lock);
156 }
157 
159 {
161 }
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 */
169 void 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  */
332 static 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 
344 typedef 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 
356 typedef 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  */
377 static 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 
439 static 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 
452 static 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  */
469 static 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  */
671 static 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 }
PKT_DROP_REASON_DEFRAG_MEMCAP
@ PKT_DROP_REASON_DEFRAG_MEMCAP
Definition: decode.h:384
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:132
DefragLookupTrackerFromHash
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
Definition: defrag-hash.c:620
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:136
DefragHashKey4
struct DefragHashKey4_ DefragHashKey4
SCConfValIsTrue
int SCConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:551
IPV6_EXTHDR_GET_FH_ID
#define IPV6_EXTHDR_GET_FH_ID(p)
Definition: decode-ipv6.h:103
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:166
DefragHashKey4_::src
uint32_t src
Definition: defrag-hash.c:347
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:122
DefragHashKey6_::u32
uint32_t u32[11]
Definition: defrag-hash.c:364
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
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:275
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:626
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
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:349
DefragHashKey4_::id
uint32_t id
Definition: defrag-hash.c:348
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:350
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:158
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
DefragTrackerGetMemuse
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition: defrag-hash.c:74
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:300
DefragTrackerMoveToSpare
void DefragTrackerMoveToSpare(DefragTracker *h)
Definition: defrag-hash.c:85
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:985
DefragConfig_::prealloc
uint32_t prealloc
Definition: defrag-hash.h:72
DefragHashKey6_::src
uint32_t src[4]
Definition: defrag-hash.c:359
DecodeThreadVars_::counter_defrag_tracker_timeout
uint16_t counter_defrag_tracker_timeout
Definition: decode.h:1026
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:361
Packet_::ts
SCTime_t ts
Definition: decode.h:555
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:119
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
ExceptionPolicyCounters_::eps_id
uint16_t eps_id[EXCEPTION_POLICY_MAX]
Definition: util-exception-policy-types.h:53
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
DefragTrackerTimedOut
int DefragTrackerTimedOut(DefragTracker *dt, SCTime_t ts)
Definition: defrag-timeout.c:39
DEFRAG_DEFAULT_HASHSIZE
#define DEFRAG_DEFAULT_HASHSIZE
Definition: defrag-hash.c:163
StringParseUint32
int StringParseUint32(uint32_t *res, int base, size_t len, const char *str)
Definition: util-byte.c:313
DefragHashKey6_::dst
uint32_t dst[4]
Definition: defrag-hash.c:359
DecodeThreadVars_::counter_defrag_tracker_hard_reuse
uint16_t counter_defrag_tracker_hard_reuse
Definition: decode.h:1025
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:317
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
Packet_
Definition: decode.h:501
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:169
DEFRAG_DEFAULT_MEMCAP
#define DEFRAG_DEFAULT_MEMCAP
Definition: defrag-hash.c:164
DefragHashKey4_::u32
uint32_t u32[5]
Definition: defrag-hash.c:352
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:152
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:33
DecodeThreadVars_::counter_defrag_memcap_eps
ExceptionPolicyCounters counter_defrag_memcap_eps
Definition: decode.h:1027
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:350
defrag-stack.h
DefragHashKey4_
Definition: defrag-hash.c:344
DefragHashKey6_
Definition: defrag-hash.c:356
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:432
FatalError
#define FatalError(...)
Definition: util-debug.h:510
util-hash-lookup3.h
DRLOCK_TRYLOCK
#define DRLOCK_TRYLOCK(fb)
Definition: defrag-hash.h:54
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
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:267
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:963
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:165
DefragTrackerDecrUsecnt
#define DefragTrackerDecrUsecnt(dt)
Definition: defrag-hash.c:124
defrag-hash.h
Packet_::dst
Address dst
Definition: decode.h:506
DefragHashKey6_::id
uint32_t id
Definition: defrag-hash.c:360
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:528
likely
#define likely(expr)
Definition: util-optimize.h:32
id
uint32_t id
Definition: detect-flowbits.c:938
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Definition: defrag-hash.c:525
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:292
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:127
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, defrag_memuse)
DefragHashKey6_::pad
uint16_t pad[1]
Definition: defrag-hash.c:362
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:243
ExceptionPolicy
ExceptionPolicy
Definition: util-exception-policy-types.h:25
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
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:347
DefragGetMemcapExceptionPolicy
enum ExceptionPolicy DefragGetMemcapExceptionPolicy(void)
Definition: defrag-hash.c:80
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:102
Packet_::src
Address src
Definition: decode.h:505
SCMutexTrylock
#define SCMutexTrylock(mut)
Definition: threads-debug.h:118
DecodeThreadVars_::counter_defrag_tracker_soft_reuse
uint16_t counter_defrag_tracker_soft_reuse
Definition: decode.h:1024