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 ((ConfGet("defrag.memcap", &conf_val)) == 1)
194  {
195  if (ParseSizeStringU64(conf_val, &defrag_memcap) < 0) {
196  SCLogError("Error parsing defrag.memcap "
197  "from conf file - %s. Killing engine",
198  conf_val);
199  exit(EXIT_FAILURE);
200  } else {
201  SC_ATOMIC_SET(defrag_config.memcap, defrag_memcap);
202  }
203  }
204  if ((ConfGet("defrag.hash-size", &conf_val)) == 1)
205  {
206  if (StringParseUint32(&configval, 10, strlen(conf_val),
207  conf_val) > 0) {
208  defrag_config.hash_size = configval;
209  } else {
210  WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size);
211  }
212  }
213 
214 
215  if ((ConfGet("defrag.trackers", &conf_val)) == 1)
216  {
217  if (StringParseUint32(&configval, 10, strlen(conf_val),
218  conf_val) > 0) {
219  defrag_config.prealloc = configval;
220  } else {
221  WarnInvalidConfEntry("defrag.trackers", "%"PRIu32, defrag_config.prealloc);
222  }
223  }
224  SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: "
225  "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(defrag_config.memcap),
227 
228  /* alloc hash memory */
229  uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow);
230  if (!(DEFRAG_CHECK_MEMCAP(hash_size))) {
231  SCLogError("allocating defrag hash failed: "
232  "max defrag memcap is smaller than projected hash size. "
233  "Memcap: %" PRIu64 ", Hash table size %" PRIu64 ". Calculate "
234  "total hash size by multiplying \"defrag.hash-size\" with %" PRIuMAX ", "
235  "which is the hash bucket size.",
236  SC_ATOMIC_GET(defrag_config.memcap), hash_size,
237  (uintmax_t)sizeof(DefragTrackerHashRow));
238  exit(EXIT_FAILURE);
239  }
241  if (unlikely(defragtracker_hash == NULL)) {
242  FatalError("Fatal error encountered in DefragTrackerInitConfig. Exiting...");
243  }
245 
246  uint32_t i = 0;
247  for (i = 0; i < defrag_config.hash_size; i++) {
249  }
250  (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow)));
251 
252  if (!quiet) {
253  SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... "
254  "%" PRIu32 " buckets of size %" PRIuMAX "",
255  SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size,
256  (uintmax_t)sizeof(DefragTrackerHashRow));
257  }
258 
259  if ((ConfGet("defrag.prealloc", &conf_val)) == 1)
260  {
261  if (ConfValIsTrue(conf_val)) {
262  /* pre allocate defrag trackers */
263  for (i = 0; i < defrag_config.prealloc; i++) {
264  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
265  SCLogError("preallocating defrag trackers failed: "
266  "max defrag memcap reached. Memcap %" PRIu64 ", "
267  "Memuse %" PRIu64 ".",
269  ((uint64_t)SC_ATOMIC_GET(defrag_memuse) +
270  (uint64_t)sizeof(DefragTracker)));
271  exit(EXIT_FAILURE);
272  }
273 
274  DefragTracker *h = DefragTrackerAlloc();
275  if (h == NULL) {
276  SCLogError("preallocating defrag failed: %s", strerror(errno));
277  exit(EXIT_FAILURE);
278  }
279  DefragTrackerEnqueue(&defragtracker_spare_q,h);
280  }
281  if (!quiet) {
282  SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "",
283  defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker));
284  }
285  }
286  }
287 
288  if (!quiet) {
289  SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
290  SC_ATOMIC_GET(defrag_memuse), SC_ATOMIC_GET(defrag_config.memcap));
291  }
292 }
293 
294 /** \brief shutdown the flow engine
295  * \warning Not thread safe */
297 {
298  DefragTracker *dt;
299 
300  /* free spare queue */
301  while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) {
302  BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0);
303  DefragTrackerFree(dt);
304  }
305 
306  /* clear and free the hash */
307  if (defragtracker_hash != NULL) {
308  for (uint32_t u = 0; u < defrag_config.hash_size; u++) {
309  dt = defragtracker_hash[u].head;
310  while (dt) {
311  DefragTracker *n = dt->hnext;
313  DefragTrackerFree(dt);
314  dt = n;
315  }
316 
318  }
320  defragtracker_hash = NULL;
321  }
322  (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow));
323  DefragTrackerStackDestroy(&defragtracker_spare_q);
324 }
325 
326 /** \brief compare two raw ipv6 addrs
327  *
328  * \note we don't care about the real ipv6 ip's, this is just
329  * to consistently fill the DefragHashKey6 struct, without all
330  * the SCNtohl calls.
331  *
332  * \warning do not use elsewhere unless you know what you're doing.
333  * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
334  * what you are looking for.
335  */
336 static inline int DefragHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
337 {
338  for (int i = 0; i < 4; i++) {
339  if (a[i] > b[i])
340  return 1;
341  if (a[i] < b[i])
342  break;
343  }
344 
345  return 0;
346 }
347 
348 typedef struct DefragHashKey4_ {
349  union {
350  struct {
351  uint32_t src, dst;
352  uint32_t id;
354  uint16_t pad[1];
355  };
356  uint32_t u32[5];
357  };
359 
360 typedef struct DefragHashKey6_ {
361  union {
362  struct {
363  uint32_t src[4], dst[4];
364  uint32_t id;
366  uint16_t pad[1];
367  };
368  uint32_t u32[11];
369  };
371 
372 /* calculate the hash key for this packet
373  *
374  * we're using:
375  * hash_rand -- set at init time
376  * source address
377  * destination address
378  * id
379  * vlan_id
380  */
381 static inline uint32_t DefragHashGetKey(Packet *p)
382 {
383  uint32_t key;
384 
385  if (PacketIsIPv4(p)) {
386  const IPV4Hdr *ip4h = PacketGetIPv4(p);
387  DefragHashKey4 dhk = { .pad[0] = 0 };
388  if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
389  dhk.src = p->src.addr_data32[0];
390  dhk.dst = p->dst.addr_data32[0];
391  } else {
392  dhk.src = p->dst.addr_data32[0];
393  dhk.dst = p->src.addr_data32[0];
394  }
395  dhk.id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
396  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
397 
398  uint32_t hash =
399  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
400  key = hash % defrag_config.hash_size;
401  } else if (PacketIsIPv6(p)) {
402  DefragHashKey6 dhk = { .pad[0] = 0 };
403  if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
404  dhk.src[0] = p->src.addr_data32[0];
405  dhk.src[1] = p->src.addr_data32[1];
406  dhk.src[2] = p->src.addr_data32[2];
407  dhk.src[3] = p->src.addr_data32[3];
408  dhk.dst[0] = p->dst.addr_data32[0];
409  dhk.dst[1] = p->dst.addr_data32[1];
410  dhk.dst[2] = p->dst.addr_data32[2];
411  dhk.dst[3] = p->dst.addr_data32[3];
412  } else {
413  dhk.src[0] = p->dst.addr_data32[0];
414  dhk.src[1] = p->dst.addr_data32[1];
415  dhk.src[2] = p->dst.addr_data32[2];
416  dhk.src[3] = p->dst.addr_data32[3];
417  dhk.dst[0] = p->src.addr_data32[0];
418  dhk.dst[1] = p->src.addr_data32[1];
419  dhk.dst[2] = p->src.addr_data32[2];
420  dhk.dst[3] = p->src.addr_data32[3];
421  }
422  dhk.id = IPV6_EXTHDR_GET_FH_ID(p);
423  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
424 
425  uint32_t hash =
426  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
427  key = hash % defrag_config.hash_size;
428  } else {
429  key = 0;
430  }
431  return key;
432 }
433 
434 /* Since two or more trackers can have the same hash key, we need to compare
435  * the tracker with the current tracker key. */
436 #define CMP_DEFRAGTRACKER(d1, d2, id) \
437  (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
438  (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
439  (d1)->proto == PacketGetIPProto(d2) && (d1)->id == (id) && \
440  (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \
441  (d1)->vlan_id[2] == (d2)->vlan_id[2])
442 
443 static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
444 {
445  uint32_t id;
446  if (PacketIsIPv4(p)) {
447  const IPV4Hdr *ip4h = PacketGetIPv4(p);
448  id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
449  } else {
450  id = IPV6_EXTHDR_GET_FH_ID(p);
451  }
452 
453  return CMP_DEFRAGTRACKER(t, p, id);
454 }
455 
456 static void DefragExceptionPolicyStatsIncr(
458 {
459  uint16_t id = dtv->counter_defrag_memcap_eps.eps_id[policy];
460  if (likely(id > 0)) {
461  StatsIncr(tv, id);
462  }
463 }
464 
465 /**
466  * \brief Get a new defrag tracker
467  *
468  * Get a new defrag tracker. We're checking memcap first and will try to make room
469  * if the memcap is reached.
470  *
471  * \retval dt *LOCKED* tracker on success, NULL on error.
472  */
473 static DefragTracker *DefragTrackerGetNew(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
474 {
475 #ifdef DEBUG
476  if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == p->pcap_cnt) {
477  SCLogNotice("simulating memcap hit for packet %" PRIu64, p->pcap_cnt);
479  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
480  return NULL;
481  }
482 #endif
483 
484  DefragTracker *dt = NULL;
485 
486  /* get a tracker from the spare queue */
487  dt = DefragTrackerDequeue(&defragtracker_spare_q);
488  if (dt == NULL) {
489  /* If we reached the max memcap, we get a used tracker */
490  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
491  dt = DefragTrackerGetUsedDefragTracker(tv, dtv);
492  if (dt == NULL) {
494  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
495  return NULL;
496  }
497 
498  /* freed a tracker, but it's unlocked */
499  } else {
500  /* now see if we can alloc a new tracker */
501  dt = DefragTrackerAlloc();
502  if (dt == NULL) {
504  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
505  return NULL;
506  }
507 
508  /* tracker is initialized but *unlocked* */
509  }
510  } else {
511  /* tracker has been recycled before it went into the spare queue */
512 
513  /* tracker is initialized (recycled) but *unlocked* */
514  }
515 
516  (void) SC_ATOMIC_ADD(defragtracker_counter, 1);
517  SCMutexLock(&dt->lock);
518  return dt;
519 }
520 
521 /* DefragGetTrackerFromHash
522  *
523  * Hash retrieval function for trackers. Looks up the hash bucket containing the
524  * tracker pointer. Then compares the packet with the found tracker to see if it is
525  * the tracker we need. If it isn't, walk the list until the right tracker is found.
526  *
527  * returns a *LOCKED* tracker or NULL
528  */
530 {
531  DefragTracker *dt = NULL;
532 
533  /* get the key to our bucket */
534  uint32_t key = DefragHashGetKey(p);
535  /* get our hash bucket and lock it */
537  DRLOCK_LOCK(hb);
538 
539  /* see if the bucket already has a tracker */
540  if (hb->head == NULL) {
541  dt = DefragTrackerGetNew(tv, dtv, p);
542  if (dt == NULL) {
543  DRLOCK_UNLOCK(hb);
544  return NULL;
545  }
546 
547  /* tracker is locked */
548  hb->head = dt;
549 
550  /* got one, now lock, initialize and return */
551  DefragTrackerInit(dt,p);
552 
553  DRLOCK_UNLOCK(hb);
554  return dt;
555  }
556 
557  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
558  DefragTracker *prev_dt = NULL;
559  dt = hb->head;
560 
561  do {
562  DefragTracker *next_dt = NULL;
563 
564  SCMutexLock(&dt->lock);
565  if (DefragTrackerTimedOut(dt, p->ts)) {
566  next_dt = dt->hnext;
567  dt->hnext = NULL;
568  if (prev_dt) {
569  prev_dt->hnext = next_dt;
570  } else {
571  hb->head = next_dt;
572  }
574  SCMutexUnlock(&dt->lock);
575 
578  goto tracker_removed;
579  } else if (!dt->remove && DefragTrackerCompare(dt, p)) {
580  /* found our tracker, keep locked & return */
581  (void)DefragTrackerIncrUsecnt(dt);
582  DRLOCK_UNLOCK(hb);
583  return dt;
584  }
585  SCMutexUnlock(&dt->lock);
586  /* unless we removed 'dt', prev_dt needs to point to
587  * current 'dt' when adding a new tracker below. */
588  prev_dt = dt;
589  next_dt = dt->hnext;
590 
591  tracker_removed:
592  if (next_dt == NULL) {
593  dt = DefragTrackerGetNew(tv, dtv, p);
594  if (dt == NULL) {
595  DRLOCK_UNLOCK(hb);
596  return NULL;
597  }
598  dt->hnext = hb->head;
599  hb->head = dt;
600 
601  /* tracker is locked */
602 
603  /* initialize and return */
604  DefragTrackerInit(dt, p);
605 
606  DRLOCK_UNLOCK(hb);
607  return dt;
608  }
609 
610  dt = next_dt;
611  } while (dt != NULL);
612 
613  /* should be unreachable */
614  BUG_ON(1);
615  return NULL;
616 }
617 
618 /** \brief look up a tracker in the hash
619  *
620  * \param a address to look up
621  *
622  * \retval h *LOCKED* tracker or NULL
623  */
625 {
626  DefragTracker *dt = NULL;
627 
628  /* get the key to our bucket */
629  uint32_t key = DefragHashGetKey(p);
630  /* get our hash bucket and lock it */
632  DRLOCK_LOCK(hb);
633 
634  /* see if the bucket already has a tracker */
635  if (hb->head == NULL) {
636  DRLOCK_UNLOCK(hb);
637  return dt;
638  }
639 
640  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
641  dt = hb->head;
642 
643  do {
644  if (!dt->remove && DefragTrackerCompare(dt, p)) {
645  /* found our tracker, lock & return */
646  SCMutexLock(&dt->lock);
647  (void)DefragTrackerIncrUsecnt(dt);
648  DRLOCK_UNLOCK(hb);
649  return dt;
650 
651  } else if (dt->hnext == NULL) {
652  DRLOCK_UNLOCK(hb);
653  return NULL;
654  }
655 
656  dt = dt->hnext;
657  } while (dt != NULL);
658 
659  /* should be unreachable */
660  BUG_ON(1);
661  return NULL;
662 }
663 
664 /** \internal
665  * \brief Get a tracker from the hash directly.
666  *
667  * Called in conditions where the spare queue is empty and memcap is reached.
668  *
669  * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes
670  * sure we don't start at the top each time since that would clear the top of
671  * the hash leading to longer and longer search times under high pressure (observed).
672  *
673  * \retval dt tracker or NULL
674  */
675 static DefragTracker *DefragTrackerGetUsedDefragTracker(ThreadVars *tv, const DecodeThreadVars *dtv)
676 {
677  uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size;
678  uint32_t cnt = defrag_config.hash_size;
679 
680  while (cnt--) {
681  if (++idx >= defrag_config.hash_size)
682  idx = 0;
683 
685 
686  if (DRLOCK_TRYLOCK(hb) != 0)
687  continue;
688 
689  DefragTracker *dt = hb->head;
690  if (dt == NULL) {
691  DRLOCK_UNLOCK(hb);
692  continue;
693  }
694 
695  if (SCMutexTrylock(&dt->lock) != 0) {
696  DRLOCK_UNLOCK(hb);
697  continue;
698  }
699 
700  /** never prune a tracker that is used by a packets
701  * we are currently processing in one of the threads */
702  if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
703  DRLOCK_UNLOCK(hb);
704  SCMutexUnlock(&dt->lock);
705  continue;
706  }
707 
708  /* only count "forced" reuse */
709  bool incr_reuse_cnt = !dt->remove;
710 
711  /* remove from the hash */
712  hb->head = dt->hnext;
713 
714  dt->hnext = NULL;
715  DRLOCK_UNLOCK(hb);
716 
718 
719  SCMutexUnlock(&dt->lock);
720 
721  if (incr_reuse_cnt) {
723  } else {
725  }
726 
727  (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt));
728  return dt;
729  }
730 
731  return NULL;
732 }
PKT_DROP_REASON_DEFRAG_MEMCAP
@ PKT_DROP_REASON_DEFRAG_MEMCAP
Definition: decode.h:363
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:624
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:69
DefragHashKey4
struct DefragHashKey4_ DefragHashKey4
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:351
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:368
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:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:594
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:190
DefragHashKey4_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: defrag-hash.c:353
DefragHashKey4_::id
uint32_t id
Definition: defrag-hash.c:352
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:332
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:232
DefragTrackerMoveToSpare
void DefragTrackerMoveToSpare(DefragTracker *h)
Definition: defrag-hash.c:85
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:536
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:986
DefragConfig_::prealloc
uint32_t prealloc
Definition: defrag-hash.h:72
DefragHashKey6_::src
uint32_t src[4]
Definition: defrag-hash.c:363
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
DecodeThreadVars_::counter_defrag_tracker_timeout
uint16_t counter_defrag_tracker_timeout
Definition: decode.h:990
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:365
Packet_::ts
SCTime_t ts
Definition: decode.h:523
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:45
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:363
DecodeThreadVars_::counter_defrag_tracker_hard_reuse
uint16_t counter_defrag_tracker_hard_reuse
Definition: decode.h:989
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:300
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:475
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:356
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:991
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:354
defrag-stack.h
DefragHashKey4_
Definition: defrag-hash.c:348
DefragHashKey6_
Definition: defrag-hash.c:360
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:436
FatalError
#define FatalError(...)
Definition: util-debug.h:502
DefragTrackerStack_::len
uint32_t len
Definition: defrag-stack.h:43
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:261
SCFree
#define SCFree(p)
Definition: util-mem.h:61
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:931
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:480
DefragHashKey6_::id
uint32_t id
Definition: defrag-hash.c:364
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:502
likely
#define likely(expr)
Definition: util-optimize.h:32
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Definition: defrag-hash.c:529
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:296
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:123
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, defrag_memuse)
DefragHashKey6_::pad
uint16_t pad[1]
Definition: defrag-hash.c:366
SCLogNotice
#define SCLogNotice(...)
Macro used to log NOTICE messages.
Definition: util-debug.h:237
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:351
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:479
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:988