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  defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker));
279  }
280  }
281  }
282 
283  if (!quiet) {
284  SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
285  SC_ATOMIC_GET(defrag_memuse), SC_ATOMIC_GET(defrag_config.memcap));
286  }
287 }
288 
289 /** \brief shutdown the flow engine
290  * \warning Not thread safe */
292 {
293  DefragTracker *dt;
294 
295  /* free spare queue */
296  while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) {
297  BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0);
298  DefragTrackerFree(dt);
299  }
300 
301  /* clear and free the hash */
302  if (defragtracker_hash != NULL) {
303  for (uint32_t u = 0; u < defrag_config.hash_size; u++) {
304  dt = defragtracker_hash[u].head;
305  while (dt) {
306  DefragTracker *n = dt->hnext;
308  DefragTrackerFree(dt);
309  dt = n;
310  }
311 
313  }
315  defragtracker_hash = NULL;
316  }
317  (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow));
318  DefragTrackerStackDestroy(&defragtracker_spare_q);
319 }
320 
321 /** \brief compare two raw ipv6 addrs
322  *
323  * \note we don't care about the real ipv6 ip's, this is just
324  * to consistently fill the DefragHashKey6 struct, without all
325  * the SCNtohl calls.
326  *
327  * \warning do not use elsewhere unless you know what you're doing.
328  * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
329  * what you are looking for.
330  */
331 static inline int DefragHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
332 {
333  for (int i = 0; i < 4; i++) {
334  if (a[i] > b[i])
335  return 1;
336  if (a[i] < b[i])
337  break;
338  }
339 
340  return 0;
341 }
342 
343 typedef struct DefragHashKey4_ {
344  union {
345  struct {
346  uint32_t src, dst;
347  uint32_t id;
349  uint16_t pad[1];
350  };
351  uint32_t u32[5];
352  };
354 
355 typedef struct DefragHashKey6_ {
356  union {
357  struct {
358  uint32_t src[4], dst[4];
359  uint32_t id;
361  uint16_t pad[1];
362  };
363  uint32_t u32[11];
364  };
366 
367 /* calculate the hash key for this packet
368  *
369  * we're using:
370  * hash_rand -- set at init time
371  * source address
372  * destination address
373  * id
374  * vlan_id
375  */
376 static inline uint32_t DefragHashGetKey(Packet *p)
377 {
378  uint32_t key;
379 
380  if (PacketIsIPv4(p)) {
381  const IPV4Hdr *ip4h = PacketGetIPv4(p);
382  DefragHashKey4 dhk = { .pad[0] = 0 };
383  if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
384  dhk.src = p->src.addr_data32[0];
385  dhk.dst = p->dst.addr_data32[0];
386  } else {
387  dhk.src = p->dst.addr_data32[0];
388  dhk.dst = p->src.addr_data32[0];
389  }
390  dhk.id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
391  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
392 
393  uint32_t hash =
394  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
395  key = hash % defrag_config.hash_size;
396  } else if (PacketIsIPv6(p)) {
397  DefragHashKey6 dhk = { .pad[0] = 0 };
398  if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
399  dhk.src[0] = p->src.addr_data32[0];
400  dhk.src[1] = p->src.addr_data32[1];
401  dhk.src[2] = p->src.addr_data32[2];
402  dhk.src[3] = p->src.addr_data32[3];
403  dhk.dst[0] = p->dst.addr_data32[0];
404  dhk.dst[1] = p->dst.addr_data32[1];
405  dhk.dst[2] = p->dst.addr_data32[2];
406  dhk.dst[3] = p->dst.addr_data32[3];
407  } else {
408  dhk.src[0] = p->dst.addr_data32[0];
409  dhk.src[1] = p->dst.addr_data32[1];
410  dhk.src[2] = p->dst.addr_data32[2];
411  dhk.src[3] = p->dst.addr_data32[3];
412  dhk.dst[0] = p->src.addr_data32[0];
413  dhk.dst[1] = p->src.addr_data32[1];
414  dhk.dst[2] = p->src.addr_data32[2];
415  dhk.dst[3] = p->src.addr_data32[3];
416  }
417  dhk.id = IPV6_EXTHDR_GET_FH_ID(p);
418  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
419 
420  uint32_t hash =
421  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
422  key = hash % defrag_config.hash_size;
423  } else {
424  key = 0;
425  }
426  return key;
427 }
428 
429 /* Since two or more trackers can have the same hash key, we need to compare
430  * the tracker with the current tracker key. */
431 #define CMP_DEFRAGTRACKER(d1, d2, id) \
432  (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
433  (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
434  (d1)->proto == PacketGetIPProto(d2) && (d1)->id == (id) && \
435  (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \
436  (d1)->vlan_id[2] == (d2)->vlan_id[2])
437 
438 static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
439 {
440  uint32_t id;
441  if (PacketIsIPv4(p)) {
442  const IPV4Hdr *ip4h = PacketGetIPv4(p);
443  id = (uint32_t)IPV4_GET_RAW_IPID(ip4h);
444  } else {
445  id = IPV6_EXTHDR_GET_FH_ID(p);
446  }
447 
448  return CMP_DEFRAGTRACKER(t, p, id);
449 }
450 
451 static void DefragExceptionPolicyStatsIncr(
453 {
454  uint16_t id = dtv->counter_defrag_memcap_eps.eps_id[policy];
455  if (likely(id > 0)) {
456  StatsIncr(tv, id);
457  }
458 }
459 
460 /**
461  * \brief Get a new defrag tracker
462  *
463  * Get a new defrag tracker. We're checking memcap first and will try to make room
464  * if the memcap is reached.
465  *
466  * \retval dt *LOCKED* tracker on success, NULL on error.
467  */
468 static DefragTracker *DefragTrackerGetNew(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
469 {
470 #ifdef DEBUG
471  if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == p->pcap_cnt) {
472  SCLogNotice("simulating memcap hit for packet %" PRIu64, p->pcap_cnt);
474  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
475  return NULL;
476  }
477 #endif
478 
479  DefragTracker *dt = NULL;
480 
481  /* get a tracker from the spare queue */
482  dt = DefragTrackerDequeue(&defragtracker_spare_q);
483  if (dt == NULL) {
484  /* If we reached the max memcap, we get a used tracker */
485  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
486  dt = DefragTrackerGetUsedDefragTracker(tv, dtv);
487  if (dt == NULL) {
489  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
490  return NULL;
491  }
492 
493  /* freed a tracker, but it's unlocked */
494  } else {
495  /* now see if we can alloc a new tracker */
496  dt = DefragTrackerAlloc();
497  if (dt == NULL) {
499  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
500  return NULL;
501  }
502 
503  /* tracker is initialized but *unlocked* */
504  }
505  } else {
506  /* tracker has been recycled before it went into the spare queue */
507 
508  /* tracker is initialized (recycled) but *unlocked* */
509  }
510 
511  (void) SC_ATOMIC_ADD(defragtracker_counter, 1);
512  SCMutexLock(&dt->lock);
513  return dt;
514 }
515 
516 /* DefragGetTrackerFromHash
517  *
518  * Hash retrieval function for trackers. Looks up the hash bucket containing the
519  * tracker pointer. Then compares the packet with the found tracker to see if it is
520  * the tracker we need. If it isn't, walk the list until the right tracker is found.
521  *
522  * returns a *LOCKED* tracker or NULL
523  */
525 {
526  DefragTracker *dt = NULL;
527 
528  /* get the key to our bucket */
529  uint32_t key = DefragHashGetKey(p);
530  /* get our hash bucket and lock it */
532  DRLOCK_LOCK(hb);
533 
534  /* see if the bucket already has a tracker */
535  if (hb->head == NULL) {
536  dt = DefragTrackerGetNew(tv, dtv, p);
537  if (dt == NULL) {
538  DRLOCK_UNLOCK(hb);
539  return NULL;
540  }
541 
542  /* tracker is locked */
543  hb->head = dt;
544 
545  /* got one, now lock, initialize and return */
546  DefragTrackerInit(dt,p);
547 
548  DRLOCK_UNLOCK(hb);
549  return dt;
550  }
551 
552  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
553  DefragTracker *prev_dt = NULL;
554  dt = hb->head;
555 
556  do {
557  DefragTracker *next_dt = NULL;
558 
559  SCMutexLock(&dt->lock);
560  if (DefragTrackerTimedOut(dt, p->ts)) {
561  next_dt = dt->hnext;
562  dt->hnext = NULL;
563  if (prev_dt) {
564  prev_dt->hnext = next_dt;
565  } else {
566  hb->head = next_dt;
567  }
569  SCMutexUnlock(&dt->lock);
570 
573  goto tracker_removed;
574  } else if (!dt->remove && DefragTrackerCompare(dt, p)) {
575  /* found our tracker, keep locked & return */
576  (void)DefragTrackerIncrUsecnt(dt);
577  DRLOCK_UNLOCK(hb);
578  return dt;
579  }
580  SCMutexUnlock(&dt->lock);
581  /* unless we removed 'dt', prev_dt needs to point to
582  * current 'dt' when adding a new tracker below. */
583  prev_dt = dt;
584  next_dt = dt->hnext;
585 
586  tracker_removed:
587  if (next_dt == NULL) {
588  dt = DefragTrackerGetNew(tv, dtv, p);
589  if (dt == NULL) {
590  DRLOCK_UNLOCK(hb);
591  return NULL;
592  }
593  dt->hnext = hb->head;
594  hb->head = dt;
595 
596  /* tracker is locked */
597 
598  /* initialize and return */
599  DefragTrackerInit(dt, p);
600 
601  DRLOCK_UNLOCK(hb);
602  return dt;
603  }
604 
605  dt = next_dt;
606  } while (dt != NULL);
607 
608  /* should be unreachable */
609  BUG_ON(1);
610  return NULL;
611 }
612 
613 /** \brief look up a tracker in the hash
614  *
615  * \param a address to look up
616  *
617  * \retval h *LOCKED* tracker or NULL
618  */
620 {
621  DefragTracker *dt = NULL;
622 
623  /* get the key to our bucket */
624  uint32_t key = DefragHashGetKey(p);
625  /* get our hash bucket and lock it */
627  DRLOCK_LOCK(hb);
628 
629  /* see if the bucket already has a tracker */
630  if (hb->head == NULL) {
631  DRLOCK_UNLOCK(hb);
632  return dt;
633  }
634 
635  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
636  dt = hb->head;
637 
638  do {
639  if (!dt->remove && DefragTrackerCompare(dt, p)) {
640  /* found our tracker, lock & return */
641  SCMutexLock(&dt->lock);
642  (void)DefragTrackerIncrUsecnt(dt);
643  DRLOCK_UNLOCK(hb);
644  return dt;
645 
646  } else if (dt->hnext == NULL) {
647  DRLOCK_UNLOCK(hb);
648  return NULL;
649  }
650 
651  dt = dt->hnext;
652  } while (dt != NULL);
653 
654  /* should be unreachable */
655  BUG_ON(1);
656  return NULL;
657 }
658 
659 /** \internal
660  * \brief Get a tracker from the hash directly.
661  *
662  * Called in conditions where the spare queue is empty and memcap is reached.
663  *
664  * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes
665  * sure we don't start at the top each time since that would clear the top of
666  * the hash leading to longer and longer search times under high pressure (observed).
667  *
668  * \retval dt tracker or NULL
669  */
670 static DefragTracker *DefragTrackerGetUsedDefragTracker(ThreadVars *tv, const DecodeThreadVars *dtv)
671 {
672  uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size;
673  uint32_t cnt = defrag_config.hash_size;
674 
675  while (cnt--) {
676  if (++idx >= defrag_config.hash_size)
677  idx = 0;
678 
680 
681  if (DRLOCK_TRYLOCK(hb) != 0)
682  continue;
683 
684  DefragTracker *dt = hb->head;
685  if (dt == NULL) {
686  DRLOCK_UNLOCK(hb);
687  continue;
688  }
689 
690  if (SCMutexTrylock(&dt->lock) != 0) {
691  DRLOCK_UNLOCK(hb);
692  continue;
693  }
694 
695  /** never prune a tracker that is used by a packets
696  * we are currently processing in one of the threads */
697  if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
698  DRLOCK_UNLOCK(hb);
699  SCMutexUnlock(&dt->lock);
700  continue;
701  }
702 
703  /* only count "forced" reuse */
704  bool incr_reuse_cnt = !dt->remove;
705 
706  /* remove from the hash */
707  hb->head = dt->hnext;
708 
709  dt->hnext = NULL;
710  DRLOCK_UNLOCK(hb);
711 
713 
714  SCMutexUnlock(&dt->lock);
715 
716  if (incr_reuse_cnt) {
718  } else {
720  }
721 
722  (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt));
723  return dt;
724  }
725 
726  return NULL;
727 }
PKT_DROP_REASON_DEFRAG_MEMCAP
@ PKT_DROP_REASON_DEFRAG_MEMCAP
Definition: decode.h:369
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:619
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:346
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:363
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:609
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:348
DefragHashKey4_::id
uint32_t id
Definition: defrag-hash.c:347
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:358
DecodeThreadVars_::counter_defrag_tracker_timeout
uint16_t counter_defrag_tracker_timeout
Definition: decode.h:1006
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:360
Packet_::ts
SCTime_t ts
Definition: decode.h:538
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:358
DecodeThreadVars_::counter_defrag_tracker_hard_reuse
uint16_t counter_defrag_tracker_hard_reuse
Definition: decode.h:1005
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:309
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:484
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:351
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:1007
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:349
defrag-stack.h
DefragHashKey4_
Definition: defrag-hash.c:343
DefragHashKey6_
Definition: defrag-hash.c:355
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:431
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:946
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:489
DefragHashKey6_::id
uint32_t id
Definition: defrag-hash.c:359
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:511
likely
#define likely(expr)
Definition: util-optimize.h:32
id
uint32_t id
Definition: detect-flowbits.c:933
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Definition: defrag-hash.c:524
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:291
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:361
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:346
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:488
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:1004