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-queue.h"
22 #include "defrag-config.h"
23 #include "util-random.h"
24 #include "util-byte.h"
25 #include "util-misc.h"
26 #include "util-hash-lookup3.h"
27 
28 /** defrag tracker hash table */
31 SC_ATOMIC_DECLARE(uint64_t,defrag_memuse);
32 SC_ATOMIC_DECLARE(unsigned int,defragtracker_counter);
33 SC_ATOMIC_DECLARE(unsigned int,defragtracker_prune_idx);
34 
35 static DefragTracker *DefragTrackerGetUsedDefragTracker(void);
36 
37 /** queue with spare tracker */
38 static DefragTrackerQueue defragtracker_spare_q;
39 
40 /**
41  * \brief Update memcap value
42  *
43  * \param size new memcap value
44  */
45 int DefragTrackerSetMemcap(uint64_t size)
46 {
47  if ((uint64_t)SC_ATOMIC_GET(defrag_memuse) < size) {
48  SC_ATOMIC_SET(defrag_config.memcap, size);
49  return 1;
50  }
51 
52  return 0;
53 }
54 
55 /**
56  * \brief Return memcap value
57  *
58  * \retval memcap value
59  */
60 uint64_t DefragTrackerGetMemcap(void)
61 {
62  uint64_t memcapcopy = SC_ATOMIC_GET(defrag_config.memcap);
63  return memcapcopy;
64 }
65 
66 /**
67  * \brief Return memuse value
68  *
69  * \retval memuse value
70  */
71 uint64_t DefragTrackerGetMemuse(void)
72 {
73  uint64_t memusecopy = (uint64_t)SC_ATOMIC_GET(defrag_memuse);
74  return memusecopy;
75 }
76 
78 {
80 }
81 
83 {
84  DefragTrackerEnqueue(&defragtracker_spare_q, h);
85  (void) SC_ATOMIC_SUB(defragtracker_counter, 1);
86 }
87 
88 static DefragTracker *DefragTrackerAlloc(void)
89 {
90  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
91  return NULL;
92  }
93 
94  (void) SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker));
95 
96  DefragTracker *dt = SCCalloc(1, sizeof(DefragTracker));
97  if (unlikely(dt == NULL))
98  goto error;
99 
100  SCMutexInit(&dt->lock, NULL);
101  SC_ATOMIC_INIT(dt->use_cnt);
102  return dt;
103 
104 error:
105  return NULL;
106 }
107 
108 static void DefragTrackerFree(DefragTracker *dt)
109 {
110  if (dt != NULL) {
112 
113  SCMutexDestroy(&dt->lock);
114  SCFree(dt);
115  (void) SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker));
116  }
117 }
118 
119 #define DefragTrackerIncrUsecnt(dt) \
120  SC_ATOMIC_ADD((dt)->use_cnt, 1)
121 #define DefragTrackerDecrUsecnt(dt) \
122  SC_ATOMIC_SUB((dt)->use_cnt, 1)
123 
124 static void DefragTrackerInit(DefragTracker *dt, Packet *p)
125 {
126  /* copy address */
127  COPY_ADDRESS(&p->src, &dt->src_addr);
128  COPY_ADDRESS(&p->dst, &dt->dst_addr);
129 
130  if (PKT_IS_IPV4(p)) {
131  dt->id = (int32_t)IPV4_GET_IPID(p);
132  dt->af = AF_INET;
133  } else {
134  dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p);
135  dt->af = AF_INET6;
136  }
137  dt->proto = IP_GET_IPPROTO(p);
138  memcpy(&dt->vlan_id[0], &p->vlan_id[0], sizeof(dt->vlan_id));
139  dt->policy = DefragGetOsPolicy(p);
141  dt->remove = 0;
142  dt->seen_last = 0;
143 
144  (void) DefragTrackerIncrUsecnt(dt);
145 }
146 
148 {
149  (void) DefragTrackerDecrUsecnt(t);
150  SCMutexUnlock(&t->lock);
151 }
152 
154 {
156 }
157 
158 #define DEFRAG_DEFAULT_HASHSIZE 4096
159 #define DEFRAG_DEFAULT_MEMCAP 16777216
160 #define DEFRAG_DEFAULT_PREALLOC 1000
161 
162 /** \brief initialize the configuration
163  * \warning Not thread safe */
164 void DefragInitConfig(bool quiet)
165 {
166  SCLogDebug("initializing defrag engine...");
167 
168  memset(&defrag_config, 0, sizeof(defrag_config));
169  //SC_ATOMIC_INIT(flow_flags);
170  SC_ATOMIC_INIT(defragtracker_counter);
171  SC_ATOMIC_INIT(defrag_memuse);
172  SC_ATOMIC_INIT(defragtracker_prune_idx);
174  DefragTrackerQueueInit(&defragtracker_spare_q);
175 
176  /* set defaults */
177  defrag_config.hash_rand = (uint32_t)RandomGet();
181  defrag_config.memcap_policy = ExceptionPolicyParse("defrag.memcap-policy", false);
182 
183  /* Check if we have memcap and hash_size defined at config */
184  const char *conf_val;
185  uint32_t configval = 0;
186 
187  uint64_t defrag_memcap;
188  /** set config values for memcap, prealloc and hash_size */
189  if ((ConfGet("defrag.memcap", &conf_val)) == 1)
190  {
191  if (ParseSizeStringU64(conf_val, &defrag_memcap) < 0) {
192  SCLogError("Error parsing defrag.memcap "
193  "from conf file - %s. Killing engine",
194  conf_val);
195  exit(EXIT_FAILURE);
196  } else {
197  SC_ATOMIC_SET(defrag_config.memcap, defrag_memcap);
198  }
199  }
200  if ((ConfGet("defrag.hash-size", &conf_val)) == 1)
201  {
202  if (StringParseUint32(&configval, 10, strlen(conf_val),
203  conf_val) > 0) {
204  defrag_config.hash_size = configval;
205  } else {
206  WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size);
207  }
208  }
209 
210 
211  if ((ConfGet("defrag.trackers", &conf_val)) == 1)
212  {
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 ((ConfGet("defrag.prealloc", &conf_val)) == 1)
256  {
257  if (ConfValIsTrue(conf_val)) {
258  /* pre allocate defrag trackers */
259  for (i = 0; i < defrag_config.prealloc; i++) {
260  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
261  SCLogError("preallocating defrag trackers failed: "
262  "max defrag memcap reached. Memcap %" PRIu64 ", "
263  "Memuse %" PRIu64 ".",
265  ((uint64_t)SC_ATOMIC_GET(defrag_memuse) +
266  (uint64_t)sizeof(DefragTracker)));
267  exit(EXIT_FAILURE);
268  }
269 
270  DefragTracker *h = DefragTrackerAlloc();
271  if (h == NULL) {
272  SCLogError("preallocating defrag failed: %s", strerror(errno));
273  exit(EXIT_FAILURE);
274  }
275  DefragTrackerEnqueue(&defragtracker_spare_q,h);
276  }
277  if (!quiet) {
278  SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "",
279  defragtracker_spare_q.len, (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  return;
290 }
291 
292 /** \brief print some defrag stats
293  * \warning Not thread safe */
294 static void DefragTrackerPrintStats (void)
295 {
296 }
297 
298 /** \brief shutdown the flow engine
299  * \warning Not thread safe */
301 {
302  DefragTracker *dt;
303  uint32_t u;
304 
305  DefragTrackerPrintStats();
306 
307  /* free spare queue */
308  while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) {
309  BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0);
310  DefragTrackerFree(dt);
311  }
312 
313  /* clear and free the hash */
314  if (defragtracker_hash != NULL) {
315  for (u = 0; u < defrag_config.hash_size; u++) {
316  dt = defragtracker_hash[u].head;
317  while (dt) {
318  DefragTracker *n = dt->hnext;
320  DefragTrackerFree(dt);
321  dt = n;
322  }
323 
325  }
327  defragtracker_hash = NULL;
328  }
329  (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow));
330  DefragTrackerQueueDestroy(&defragtracker_spare_q);
331  return;
332 }
333 
334 /** \brief compare two raw ipv6 addrs
335  *
336  * \note we don't care about the real ipv6 ip's, this is just
337  * to consistently fill the DefragHashKey6 struct, without all
338  * the SCNtohl calls.
339  *
340  * \warning do not use elsewhere unless you know what you're doing.
341  * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
342  * what you are looking for.
343  */
344 static inline int DefragHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
345 {
346  for (int i = 0; i < 4; i++) {
347  if (a[i] > b[i])
348  return 1;
349  if (a[i] < b[i])
350  break;
351  }
352 
353  return 0;
354 }
355 
356 typedef struct DefragHashKey4_ {
357  union {
358  struct {
359  uint32_t src, dst;
360  uint32_t id;
362  uint16_t pad[1];
363  };
364  uint32_t u32[5];
365  };
367 
368 typedef struct DefragHashKey6_ {
369  union {
370  struct {
371  uint32_t src[4], dst[4];
372  uint32_t id;
374  uint16_t pad[1];
375  };
376  uint32_t u32[11];
377  };
379 
380 /* calculate the hash key for this packet
381  *
382  * we're using:
383  * hash_rand -- set at init time
384  * source address
385  * destination address
386  * id
387  * vlan_id
388  */
389 static inline uint32_t DefragHashGetKey(Packet *p)
390 {
391  uint32_t key;
392 
393  if (p->ip4h != NULL) {
394  DefragHashKey4 dhk = { .pad[0] = 0 };
395  if (p->src.addr_data32[0] > p->dst.addr_data32[0]) {
396  dhk.src = p->src.addr_data32[0];
397  dhk.dst = p->dst.addr_data32[0];
398  } else {
399  dhk.src = p->dst.addr_data32[0];
400  dhk.dst = p->src.addr_data32[0];
401  }
402  dhk.id = (uint32_t)IPV4_GET_IPID(p);
403  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
404 
405  uint32_t hash =
406  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
407  key = hash % defrag_config.hash_size;
408  } else if (p->ip6h != NULL) {
409  DefragHashKey6 dhk = { .pad[0] = 0 };
410  if (DefragHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
411  dhk.src[0] = p->src.addr_data32[0];
412  dhk.src[1] = p->src.addr_data32[1];
413  dhk.src[2] = p->src.addr_data32[2];
414  dhk.src[3] = p->src.addr_data32[3];
415  dhk.dst[0] = p->dst.addr_data32[0];
416  dhk.dst[1] = p->dst.addr_data32[1];
417  dhk.dst[2] = p->dst.addr_data32[2];
418  dhk.dst[3] = p->dst.addr_data32[3];
419  } else {
420  dhk.src[0] = p->dst.addr_data32[0];
421  dhk.src[1] = p->dst.addr_data32[1];
422  dhk.src[2] = p->dst.addr_data32[2];
423  dhk.src[3] = p->dst.addr_data32[3];
424  dhk.dst[0] = p->src.addr_data32[0];
425  dhk.dst[1] = p->src.addr_data32[1];
426  dhk.dst[2] = p->src.addr_data32[2];
427  dhk.dst[3] = p->src.addr_data32[3];
428  }
429  dhk.id = IPV6_EXTHDR_GET_FH_ID(p);
430  memcpy(&dhk.vlan_id[0], &p->vlan_id[0], sizeof(dhk.vlan_id));
431 
432  uint32_t hash =
433  hashword(dhk.u32, sizeof(dhk.u32) / sizeof(uint32_t), defrag_config.hash_rand);
434  key = hash % defrag_config.hash_size;
435  } else
436  key = 0;
437 
438  return key;
439 }
440 
441 /* Since two or more trackers can have the same hash key, we need to compare
442  * the tracker with the current tracker key. */
443 #define CMP_DEFRAGTRACKER(d1, d2, id) \
444  (((CMP_ADDR(&(d1)->src_addr, &(d2)->src) && CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
445  (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
446  (d1)->proto == IP_GET_IPPROTO(d2) && (d1)->id == (id) && \
447  (d1)->vlan_id[0] == (d2)->vlan_id[0] && (d1)->vlan_id[1] == (d2)->vlan_id[1] && \
448  (d1)->vlan_id[2] == (d2)->vlan_id[2])
449 
450 static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
451 {
452  uint32_t id;
453  if (PKT_IS_IPV4(p)) {
454  id = (uint32_t)IPV4_GET_IPID(p);
455  } else {
456  id = IPV6_EXTHDR_GET_FH_ID(p);
457  }
458 
459  return CMP_DEFRAGTRACKER(t, p, id);
460 }
461 
462 static void DefragExceptionPolicyStatsIncr(
464 {
465  uint16_t id = dtv->counter_defrag_memcap_eps.eps_id[policy];
466  if (likely(tv && id > 0)) {
467  StatsIncr(tv, id);
468  }
469 }
470 
471 /**
472  * \brief Get a new defrag tracker
473  *
474  * Get a new defrag tracker. We're checking memcap first and will try to make room
475  * if the memcap is reached.
476  *
477  * \retval dt *LOCKED* tracker on success, NULL on error.
478  */
479 static DefragTracker *DefragTrackerGetNew(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
480 {
481 #ifdef DEBUG
482  if (g_eps_defrag_memcap != UINT64_MAX && g_eps_defrag_memcap == p->pcap_cnt) {
483  SCLogNotice("simulating memcap hit for packet %" PRIu64, p->pcap_cnt);
485  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
486  return NULL;
487  }
488 #endif
489 
490  DefragTracker *dt = NULL;
491 
492  /* get a tracker from the spare queue */
493  dt = DefragTrackerDequeue(&defragtracker_spare_q);
494  if (dt == NULL) {
495  /* If we reached the max memcap, we get a used tracker */
496  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
497  /* declare state of emergency */
498  //if (!(SC_ATOMIC_GET(defragtracker_flags) & DEFRAG_EMERGENCY)) {
499  // SC_ATOMIC_OR(defragtracker_flags, DEFRAG_EMERGENCY);
500 
501  /* under high load, waking up the flow mgr each time leads
502  * to high cpu usage. Flows are not timed out much faster if
503  * we check a 1000 times a second. */
504  // FlowWakeupFlowManagerThread();
505  //}
506 
507  dt = DefragTrackerGetUsedDefragTracker();
508  if (dt == NULL) {
510  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
511  return NULL;
512  }
513 
514  /* freed a tracker, but it's unlocked */
515  } else {
516  /* now see if we can alloc a new tracker */
517  dt = DefragTrackerAlloc();
518  if (dt == NULL) {
520  DefragExceptionPolicyStatsIncr(tv, dtv, defrag_config.memcap_policy);
521  return NULL;
522  }
523 
524  /* tracker is initialized but *unlocked* */
525  }
526  } else {
527  /* tracker has been recycled before it went into the spare queue */
528 
529  /* tracker is initialized (recycled) but *unlocked* */
530  }
531 
532  (void) SC_ATOMIC_ADD(defragtracker_counter, 1);
533  SCMutexLock(&dt->lock);
534  return dt;
535 }
536 
537 /* DefragGetTrackerFromHash
538  *
539  * Hash retrieval function for trackers. Looks up the hash bucket containing the
540  * tracker pointer. Then compares the packet with the found tracker to see if it is
541  * the tracker we need. If it isn't, walk the list until the right tracker is found.
542  *
543  * returns a *LOCKED* tracker or NULL
544  */
546 {
547  DefragTracker *dt = NULL;
548 
549  /* get the key to our bucket */
550  uint32_t key = DefragHashGetKey(p);
551  /* get our hash bucket and lock it */
553  DRLOCK_LOCK(hb);
554 
555  /* see if the bucket already has a tracker */
556  if (hb->head == NULL) {
557  dt = DefragTrackerGetNew(tv, dtv, p);
558  if (dt == NULL) {
559  DRLOCK_UNLOCK(hb);
560  return NULL;
561  }
562 
563  /* tracker is locked */
564  hb->head = dt;
565  hb->tail = dt;
566 
567  /* got one, now lock, initialize and return */
568  DefragTrackerInit(dt,p);
569 
570  DRLOCK_UNLOCK(hb);
571  return dt;
572  }
573 
574  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
575  dt = hb->head;
576 
577  /* see if this is the tracker we are looking for */
578  if (dt->remove || DefragTrackerCompare(dt, p) == 0) {
579  DefragTracker *pdt = NULL; /* previous tracker */
580 
581  while (dt) {
582  pdt = dt;
583  dt = dt->hnext;
584 
585  if (dt == NULL) {
586  dt = pdt->hnext = DefragTrackerGetNew(tv, dtv, p);
587  if (dt == NULL) {
588  DRLOCK_UNLOCK(hb);
589  return NULL;
590  }
591  hb->tail = dt;
592 
593  /* tracker is locked */
594 
595  dt->hprev = pdt;
596 
597  /* initialize and return */
598  DefragTrackerInit(dt,p);
599 
600  DRLOCK_UNLOCK(hb);
601  return dt;
602  }
603 
604  if (DefragTrackerCompare(dt, p) != 0) {
605  /* we found our tracker, lets put it on top of the
606  * hash list -- this rewards active trackers */
607  if (dt->hnext) {
608  dt->hnext->hprev = dt->hprev;
609  }
610  if (dt->hprev) {
611  dt->hprev->hnext = dt->hnext;
612  }
613  if (dt == hb->tail) {
614  hb->tail = dt->hprev;
615  }
616 
617  dt->hnext = hb->head;
618  dt->hprev = NULL;
619  hb->head->hprev = dt;
620  hb->head = dt;
621 
622  /* found our tracker, lock & return */
623  SCMutexLock(&dt->lock);
624  (void) DefragTrackerIncrUsecnt(dt);
625  DRLOCK_UNLOCK(hb);
626  return dt;
627  }
628  }
629  }
630 
631  /* lock & return */
632  SCMutexLock(&dt->lock);
633  (void) DefragTrackerIncrUsecnt(dt);
634  DRLOCK_UNLOCK(hb);
635  return dt;
636 }
637 
638 /** \brief look up a tracker in the hash
639  *
640  * \param a address to look up
641  *
642  * \retval h *LOCKED* tracker or NULL
643  */
645 {
646  DefragTracker *dt = NULL;
647 
648  /* get the key to our bucket */
649  uint32_t key = DefragHashGetKey(p);
650  /* get our hash bucket and lock it */
652  DRLOCK_LOCK(hb);
653 
654  /* see if the bucket already has a tracker */
655  if (hb->head == NULL) {
656  DRLOCK_UNLOCK(hb);
657  return dt;
658  }
659 
660  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
661  dt = hb->head;
662 
663  /* see if this is the tracker we are looking for */
664  if (DefragTrackerCompare(dt, p) == 0) {
665  while (dt) {
666  dt = dt->hnext;
667 
668  if (dt == NULL) {
669  DRLOCK_UNLOCK(hb);
670  return dt;
671  }
672 
673  if (DefragTrackerCompare(dt, p) != 0) {
674  /* we found our tracker, lets put it on top of the
675  * hash list -- this rewards active tracker */
676  if (dt->hnext) {
677  dt->hnext->hprev = dt->hprev;
678  }
679  if (dt->hprev) {
680  dt->hprev->hnext = dt->hnext;
681  }
682  if (dt == hb->tail) {
683  hb->tail = dt->hprev;
684  }
685 
686  dt->hnext = hb->head;
687  dt->hprev = NULL;
688  hb->head->hprev = dt;
689  hb->head = dt;
690 
691  /* found our tracker, lock & return */
692  SCMutexLock(&dt->lock);
693  (void) DefragTrackerIncrUsecnt(dt);
694  DRLOCK_UNLOCK(hb);
695  return dt;
696  }
697  }
698  }
699 
700  /* lock & return */
701  SCMutexLock(&dt->lock);
702  (void) DefragTrackerIncrUsecnt(dt);
703  DRLOCK_UNLOCK(hb);
704  return dt;
705 }
706 
707 /** \internal
708  * \brief Get a tracker from the hash directly.
709  *
710  * Called in conditions where the spare queue is empty and memcap is reached.
711  *
712  * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes
713  * sure we don't start at the top each time since that would clear the top of
714  * the hash leading to longer and longer search times under high pressure (observed).
715  *
716  * \retval dt tracker or NULL
717  */
718 static DefragTracker *DefragTrackerGetUsedDefragTracker(void)
719 {
720  uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size;
721  uint32_t cnt = defrag_config.hash_size;
722 
723  while (cnt--) {
724  if (++idx >= defrag_config.hash_size)
725  idx = 0;
726 
728 
729  if (DRLOCK_TRYLOCK(hb) != 0)
730  continue;
731 
732  DefragTracker *dt = hb->tail;
733  if (dt == NULL) {
734  DRLOCK_UNLOCK(hb);
735  continue;
736  }
737 
738  if (SCMutexTrylock(&dt->lock) != 0) {
739  DRLOCK_UNLOCK(hb);
740  continue;
741  }
742 
743  /** never prune a tracker that is used by a packets
744  * we are currently processing in one of the threads */
745  if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
746  DRLOCK_UNLOCK(hb);
747  SCMutexUnlock(&dt->lock);
748  continue;
749  }
750 
751  /* remove from the hash */
752  if (dt->hprev != NULL)
753  dt->hprev->hnext = dt->hnext;
754  if (dt->hnext != NULL)
755  dt->hnext->hprev = dt->hprev;
756  if (hb->head == dt)
757  hb->head = dt->hnext;
758  if (hb->tail == dt)
759  hb->tail = dt->hprev;
760 
761  dt->hnext = NULL;
762  dt->hprev = NULL;
763  DRLOCK_UNLOCK(hb);
764 
766 
767  SCMutexUnlock(&dt->lock);
768 
769  (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt));
770  return dt;
771  }
772 
773  return NULL;
774 }
775 
776 
PKT_DROP_REASON_DEFRAG_MEMCAP
@ PKT_DROP_REASON_DEFRAG_MEMCAP
Definition: decode.h:395
util-byte.h
DefragTrackerFreeFrags
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition: defrag.c:153
DefragLookupTrackerFromHash
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
Definition: defrag-hash.c:644
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:130
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:167
DefragHashKey4_::src
uint32_t src
Definition: defrag-hash.c:359
hashword
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:174
DefragTracker_::hnext
struct DefragTracker_ * hnext
Definition: defrag.h:119
defragtracker_hash
DefragTrackerHashRow * defragtracker_hash
Definition: defrag-hash.c:29
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:119
DefragHashKey6_::u32
uint32_t u32[11]
Definition: defrag-hash.c:376
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:607
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:198
DefragHashKey4_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: defrag-hash.c:361
DefragTrackerQueueDestroy
void DefragTrackerQueueDestroy(DefragTrackerQueue *q)
Destroy a tracker queue.
Definition: defrag-queue.c:57
DefragHashKey4_::id
uint32_t id
Definition: defrag-hash.c:360
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
DefragTrackerClearMemory
void DefragTrackerClearMemory(DefragTracker *dt)
Definition: defrag-hash.c:153
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
DefragTracker_::host_timeout
uint32_t host_timeout
Definition: defrag.h:111
RandomGet
long int RandomGet(void)
Definition: util-random.c:130
DefragTrackerGetMemuse
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition: defrag-hash.c:71
defrag-config.h
DefragPolicyGetHostTimeout
int DefragPolicyGetHostTimeout(Packet *p)
Definition: defrag-config.c:92
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:82
ConfValIsTrue
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:537
DefragTracker_::hprev
struct DefragTracker_ * hprev
Definition: defrag.h:120
DefragTracker_::lock
SCMutex lock
Definition: defrag.h:87
DefragConfig_::hash_size
uint32_t hash_size
Definition: defrag-hash.h:72
DefragGetOsPolicy
uint8_t DefragGetOsPolicy(Packet *p)
Get the defrag policy based on the destination address of the packet.
Definition: defrag.c:928
DefragConfig_::prealloc
uint32_t prealloc
Definition: defrag-hash.h:73
DefragHashKey6_::src
uint32_t src[4]
Definition: defrag-hash.c:371
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:335
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:30
DefragHashKey6_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: defrag-hash.c:373
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:86
DEFRAG_CHECK_MEMCAP
#define DEFRAG_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition: defrag-hash.h:84
DefragTracker_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: defrag.h:90
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:57
DefragTrackerHashRow_::tail
DefragTracker * tail
Definition: defrag-hash.h:63
DEFRAG_DEFAULT_HASHSIZE
#define DEFRAG_DEFAULT_HASHSIZE
Definition: defrag-hash.c:158
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:371
defrag-queue.h
DefragTrackerGetMemcap
uint64_t DefragTrackerGetMemcap(void)
Return memcap value.
Definition: defrag-hash.c:60
DefragTracker_::dst_addr
Address dst_addr
Definition: defrag.h:107
DefragTrackerDequeue
DefragTracker * DefragTrackerDequeue(DefragTrackerQueue *q)
remove a tracker from the queue
Definition: defrag-queue.c:101
IPV4_GET_IPID
#define IPV4_GET_IPID(p)
Definition: decode-ipv4.h:129
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:437
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
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:545
DefragInitConfig
void DefragInitConfig(bool quiet)
initialize the configuration
Definition: defrag-hash.c:164
DefragTrackerQueue_
Definition: defrag-queue.h:42
DEFRAG_DEFAULT_MEMCAP
#define DEFRAG_DEFAULT_MEMCAP
Definition: defrag-hash.c:159
DefragHashKey4_::u32
uint32_t u32[5]
Definition: defrag-hash.c:364
DefragTrackerRelease
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:147
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:74
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
DecodeThreadVars_::counter_defrag_memcap_eps
ExceptionPolicyCounters counter_defrag_memcap_eps
Definition: decode.h:741
DRLOCK_DESTROY
#define DRLOCK_DESTROY(fb)
Definition: defrag-hash.h:52
DefragTrackerQueue_::len
uint32_t len
Definition: defrag-queue.h:45
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
suricata-common.h
DefragHashKey4_::pad
uint16_t pad[1]
Definition: defrag-hash.c:362
DefragTrackerQueueInit
DefragTrackerQueue * DefragTrackerQueueInit(DefragTrackerQueue *q)
Definition: defrag-queue.c:32
DefragHashKey4_
Definition: defrag-hash.c:356
DefragHashKey6_
Definition: defrag-hash.c:368
VLAN_MAX_LAYERS
#define VLAN_MAX_LAYERS
Definition: decode-vlan.h:51
DefragConfig_
Definition: defrag-hash.h:69
CMP_DEFRAGTRACKER
#define CMP_DEFRAGTRACKER(d1, d2, id)
Definition: defrag-hash.c:443
FatalError
#define FatalError(...)
Definition: util-debug.h:502
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:45
DefragConfig_::hash_rand
uint32_t hash_rand
Definition: defrag-hash.h:71
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
DefragTrackerEnqueue
void DefragTrackerEnqueue(DefragTrackerQueue *q, DefragTracker *dt)
add a tracker to a queue
Definition: defrag-queue.c:68
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:685
DRLOCK_INIT
#define DRLOCK_INIT(fb)
Definition: defrag-hash.h:51
DefragTracker_::af
uint8_t af
Definition: defrag.h:99
IP_GET_IPPROTO
#define IP_GET_IPPROTO(p)
Definition: decode.h:258
util-random.h
DEFRAG_DEFAULT_PREALLOC
#define DEFRAG_DEFAULT_PREALLOC
Definition: defrag-hash.c:160
DefragTrackerDecrUsecnt
#define DefragTrackerDecrUsecnt(dt)
Definition: defrag-hash.c:121
defrag-hash.h
Packet_::dst
Address dst
Definition: decode.h:442
DefragHashKey6_::id
uint32_t id
Definition: defrag-hash.c:372
Packet_::vlan_id
uint16_t vlan_id[VLAN_MAX_LAYERS]
Definition: decode.h:464
likely
#define likely(expr)
Definition: util-optimize.h:32
DefragGetTrackerFromHash
DefragTracker * DefragGetTrackerFromHash(ThreadVars *tv, DecodeThreadVars *dtv, Packet *p)
Definition: defrag-hash.c:545
DefragHashShutdown
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:300
Packet_::ip6h
IPV6Hdr * ip6h
Definition: decode.h:547
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:131
SC_ATOMIC_DECLARE
SC_ATOMIC_DECLARE(uint64_t, defrag_memuse)
DefragHashKey6_::pad
uint16_t pad[1]
Definition: defrag-hash.c:374
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
PKT_IS_IPV4
#define PKT_IS_IPV4(p)
Definition: decode.h:246
DefragHashKey4_::dst
uint32_t dst
Definition: defrag-hash.c:359
DefragGetMemcapExceptionPolicy
enum ExceptionPolicy DefragGetMemcapExceptionPolicy(void)
Definition: defrag-hash.c:77
Packet_::src
Address src
Definition: decode.h:441
SCMutexTrylock
#define SCMutexTrylock(mut)
Definition: threads-debug.h:118