suricata
defrag-hash.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2012 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 static DefragTracker *DefragTrackerGetUsedDefragTracker(void);
29 
30 /** queue with spare tracker */
31 static DefragTrackerQueue defragtracker_spare_q;
32 
33 /**
34  * \brief Update memcap value
35  *
36  * \param size new memcap value
37  */
38 int DefragTrackerSetMemcap(uint64_t size)
39 {
40  if ((uint64_t)SC_ATOMIC_GET(defrag_memuse) < size) {
41  SC_ATOMIC_SET(defrag_config.memcap, size);
42  return 1;
43  }
44 
45  return 0;
46 }
47 
48 /**
49  * \brief Return memcap value
50  *
51  * \retval memcap value
52  */
53 uint64_t DefragTrackerGetMemcap(void)
54 {
55  uint64_t memcapcopy = SC_ATOMIC_GET(defrag_config.memcap);
56  return memcapcopy;
57 }
58 
59 /**
60  * \brief Return memuse value
61  *
62  * \retval memuse value
63  */
64 uint64_t DefragTrackerGetMemuse(void)
65 {
66  uint64_t memusecopy = (uint64_t)SC_ATOMIC_GET(defrag_memuse);
67  return memusecopy;
68 }
69 
71 {
72  return DefragTrackerQueueLen(&defragtracker_spare_q);
73 }
74 
76 {
77  DefragTrackerEnqueue(&defragtracker_spare_q, h);
78  (void) SC_ATOMIC_SUB(defragtracker_counter, 1);
79 }
80 
81 static DefragTracker *DefragTrackerAlloc(void)
82 {
83  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
84  return NULL;
85  }
86 
87  (void) SC_ATOMIC_ADD(defrag_memuse, sizeof(DefragTracker));
88 
89  DefragTracker *dt = SCMalloc(sizeof(DefragTracker));
90  if (unlikely(dt == NULL))
91  goto error;
92 
93  memset(dt, 0x00, sizeof(DefragTracker));
94 
95  SCMutexInit(&dt->lock, NULL);
96  SC_ATOMIC_INIT(dt->use_cnt);
97  return dt;
98 
99 error:
100  return NULL;
101 }
102 
103 static void DefragTrackerFree(DefragTracker *dt)
104 {
105  if (dt != NULL) {
107 
108  SCMutexDestroy(&dt->lock);
109  SCFree(dt);
110  (void) SC_ATOMIC_SUB(defrag_memuse, sizeof(DefragTracker));
111  }
112 }
113 
114 #define DefragTrackerIncrUsecnt(dt) \
115  SC_ATOMIC_ADD((dt)->use_cnt, 1)
116 #define DefragTrackerDecrUsecnt(dt) \
117  SC_ATOMIC_SUB((dt)->use_cnt, 1)
118 
119 static void DefragTrackerInit(DefragTracker *dt, Packet *p)
120 {
121  /* copy address */
122  COPY_ADDRESS(&p->src, &dt->src_addr);
123  COPY_ADDRESS(&p->dst, &dt->dst_addr);
124 
125  if (PKT_IS_IPV4(p)) {
126  dt->id = (int32_t)IPV4_GET_IPID(p);
127  dt->af = AF_INET;
128  } else {
129  dt->id = (int32_t)IPV6_EXTHDR_GET_FH_ID(p);
130  dt->af = AF_INET6;
131  }
132  dt->proto = IP_GET_IPPROTO(p);
133  dt->vlan_id[0] = p->vlan_id[0];
134  dt->vlan_id[1] = p->vlan_id[1];
135  dt->policy = DefragGetOsPolicy(p);
137  dt->remove = 0;
138  dt->seen_last = 0;
139 
140  (void) DefragTrackerIncrUsecnt(dt);
141 }
142 
144 {
145  (void) DefragTrackerDecrUsecnt(t);
146  SCMutexUnlock(&t->lock);
147 }
148 
150 {
152  SC_ATOMIC_DESTROY(dt->use_cnt);
153 }
154 
155 #define DEFRAG_DEFAULT_HASHSIZE 4096
156 #define DEFRAG_DEFAULT_MEMCAP 16777216
157 #define DEFRAG_DEFAULT_PREALLOC 1000
158 
159 /** \brief initialize the configuration
160  * \warning Not thread safe */
161 void DefragInitConfig(char quiet)
162 {
163  SCLogDebug("initializing defrag engine...");
164 
165  memset(&defrag_config, 0, sizeof(defrag_config));
166  //SC_ATOMIC_INIT(flow_flags);
167  SC_ATOMIC_INIT(defragtracker_counter);
168  SC_ATOMIC_INIT(defrag_memuse);
169  SC_ATOMIC_INIT(defragtracker_prune_idx);
171  DefragTrackerQueueInit(&defragtracker_spare_q);
172 
173  /* set defaults */
174  defrag_config.hash_rand = (uint32_t)RandomGet();
178 
179  /* Check if we have memcap and hash_size defined at config */
180  const char *conf_val;
181  uint32_t configval = 0;
182 
183  uint64_t defrag_memcap;
184  /** set config values for memcap, prealloc and hash_size */
185  if ((ConfGet("defrag.memcap", &conf_val)) == 1)
186  {
187  if (ParseSizeStringU64(conf_val, &defrag_memcap) < 0) {
188  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing defrag.memcap "
189  "from conf file - %s. Killing engine",
190  conf_val);
191  exit(EXIT_FAILURE);
192  } else {
193  SC_ATOMIC_SET(defrag_config.memcap, defrag_memcap);
194  }
195  }
196  if ((ConfGet("defrag.hash-size", &conf_val)) == 1)
197  {
198  if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
199  conf_val) > 0) {
200  defrag_config.hash_size = configval;
201  } else {
202  WarnInvalidConfEntry("defrag.hash-size", "%"PRIu32, defrag_config.hash_size);
203  }
204  }
205 
206 
207  if ((ConfGet("defrag.trackers", &conf_val)) == 1)
208  {
209  if (ByteExtractStringUint32(&configval, 10, strlen(conf_val),
210  conf_val) > 0) {
211  defrag_config.prealloc = configval;
212  } else {
213  WarnInvalidConfEntry("defrag.trackers", "%"PRIu32, defrag_config.prealloc);
214  }
215  }
216  SCLogDebug("DefragTracker config from suricata.yaml: memcap: %"PRIu64", hash-size: "
217  "%"PRIu32", prealloc: %"PRIu32, SC_ATOMIC_GET(defrag_config.memcap),
219 
220  /* alloc hash memory */
221  uint64_t hash_size = defrag_config.hash_size * sizeof(DefragTrackerHashRow);
222  if (!(DEFRAG_CHECK_MEMCAP(hash_size))) {
223  SCLogError(SC_ERR_DEFRAG_INIT, "allocating defrag hash failed: "
224  "max defrag memcap is smaller than projected hash size. "
225  "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
226  "total hash size by multiplying \"defrag.hash-size\" with %"PRIuMAX", "
227  "which is the hash bucket size.", SC_ATOMIC_GET(defrag_config.memcap), hash_size,
228  (uintmax_t)sizeof(DefragTrackerHashRow));
229  exit(EXIT_FAILURE);
230  }
232  if (unlikely(defragtracker_hash == NULL)) {
233  SCLogError(SC_ERR_FATAL, "Fatal error encountered in DefragTrackerInitConfig. Exiting...");
234  exit(EXIT_FAILURE);
235  }
237 
238  uint32_t i = 0;
239  for (i = 0; i < defrag_config.hash_size; i++) {
241  }
242  (void) SC_ATOMIC_ADD(defrag_memuse, (defrag_config.hash_size * sizeof(DefragTrackerHashRow)));
243 
244  if (quiet == FALSE) {
245  SCLogConfig("allocated %"PRIu64" bytes of memory for the defrag hash... "
246  "%" PRIu32 " buckets of size %" PRIuMAX "",
247  SC_ATOMIC_GET(defrag_memuse), defrag_config.hash_size,
248  (uintmax_t)sizeof(DefragTrackerHashRow));
249  }
250 
251  if ((ConfGet("defrag.prealloc", &conf_val)) == 1)
252  {
253  if (ConfValIsTrue(conf_val)) {
254  /* pre allocate defrag trackers */
255  for (i = 0; i < defrag_config.prealloc; i++) {
256  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
257  SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag trackers failed: "
258  "max defrag memcap reached. Memcap %"PRIu64", "
259  "Memuse %"PRIu64".", SC_ATOMIC_GET(defrag_config.memcap),
260  ((uint64_t)SC_ATOMIC_GET(defrag_memuse) + (uint64_t)sizeof(DefragTracker)));
261  exit(EXIT_FAILURE);
262  }
263 
264  DefragTracker *h = DefragTrackerAlloc();
265  if (h == NULL) {
266  SCLogError(SC_ERR_DEFRAG_INIT, "preallocating defrag failed: %s", strerror(errno));
267  exit(EXIT_FAILURE);
268  }
269  DefragTrackerEnqueue(&defragtracker_spare_q,h);
270  }
271  if (quiet == FALSE) {
272  SCLogConfig("preallocated %" PRIu32 " defrag trackers of size %" PRIuMAX "",
273  defragtracker_spare_q.len, (uintmax_t)sizeof(DefragTracker));
274  }
275  }
276  }
277 
278  if (quiet == FALSE) {
279  SCLogConfig("defrag memory usage: %"PRIu64" bytes, maximum: %"PRIu64,
280  SC_ATOMIC_GET(defrag_memuse), SC_ATOMIC_GET(defrag_config.memcap));
281  }
282 
283  return;
284 }
285 
286 /** \brief print some defrag stats
287  * \warning Not thread safe */
288 static void DefragTrackerPrintStats (void)
289 {
290 }
291 
292 /** \brief shutdown the flow engine
293  * \warning Not thread safe */
295 {
296  DefragTracker *dt;
297  uint32_t u;
298 
299  DefragTrackerPrintStats();
300 
301  /* free spare queue */
302  while((dt = DefragTrackerDequeue(&defragtracker_spare_q))) {
303  BUG_ON(SC_ATOMIC_GET(dt->use_cnt) > 0);
304  DefragTrackerFree(dt);
305  }
306 
307  /* clear and free the hash */
308  if (defragtracker_hash != NULL) {
309  for (u = 0; u < defrag_config.hash_size; u++) {
310  dt = defragtracker_hash[u].head;
311  while (dt) {
312  DefragTracker *n = dt->hnext;
314  DefragTrackerFree(dt);
315  dt = n;
316  }
317 
319  }
321  defragtracker_hash = NULL;
322  }
323  (void) SC_ATOMIC_SUB(defrag_memuse, defrag_config.hash_size * sizeof(DefragTrackerHashRow));
324  DefragTrackerQueueDestroy(&defragtracker_spare_q);
325 
326  SC_ATOMIC_DESTROY(defragtracker_prune_idx);
327  SC_ATOMIC_DESTROY(defrag_memuse);
328  SC_ATOMIC_DESTROY(defragtracker_counter);
330  //SC_ATOMIC_DESTROY(flow_flags);
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(uint32_t *a, uint32_t *b)
345 {
346  int i;
347 
348  for (i = 0; i < 4; i++) {
349  if (a[i] > b[i])
350  return 1;
351  if (a[i] < b[i])
352  break;
353  }
354 
355  return 0;
356 }
357 
358 typedef struct DefragHashKey4_ {
359  union {
360  struct {
361  uint32_t src, dst;
362  uint32_t id;
363  uint16_t vlan_id[2];
364  };
365  uint32_t u32[4];
366  };
368 
369 typedef struct DefragHashKey6_ {
370  union {
371  struct {
372  uint32_t src[4], dst[4];
373  uint32_t id;
374  uint16_t vlan_id[2];
375  };
376  uint32_t u32[10];
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;
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  dhk.vlan_id[0] = p->vlan_id[0];
404  dhk.vlan_id[1] = p->vlan_id[1];
405 
406  uint32_t hash = hashword(dhk.u32, 4, defrag_config.hash_rand);
407  key = hash % defrag_config.hash_size;
408  } else if (p->ip6h != NULL) {
409  DefragHashKey6 dhk;
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  dhk.vlan_id[0] = p->vlan_id[0];
431  dhk.vlan_id[1] = p->vlan_id[1];
432 
433  uint32_t hash = hashword(dhk.u32, 10, 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) && \
445  CMP_ADDR(&(d1)->dst_addr, &(d2)->dst)) || \
446  (CMP_ADDR(&(d1)->src_addr, &(d2)->dst) && \
447  CMP_ADDR(&(d1)->dst_addr, &(d2)->src))) && \
448  (d1)->proto == IP_GET_IPPROTO(d2) && \
449  (d1)->id == (id) && \
450  (d1)->vlan_id[0] == (d2)->vlan_id[0] && \
451  (d1)->vlan_id[1] == (d2)->vlan_id[1])
452 
453 static inline int DefragTrackerCompare(DefragTracker *t, Packet *p)
454 {
455  uint32_t id;
456  if (PKT_IS_IPV4(p)) {
457  id = (uint32_t)IPV4_GET_IPID(p);
458  } else {
459  id = IPV6_EXTHDR_GET_FH_ID(p);
460  }
461 
462  return CMP_DEFRAGTRACKER(t, p, id);
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 succes, NULL on error.
472  */
473 static DefragTracker *DefragTrackerGetNew(Packet *p)
474 {
475  DefragTracker *dt = NULL;
476 
477  /* get a tracker from the spare queue */
478  dt = DefragTrackerDequeue(&defragtracker_spare_q);
479  if (dt == NULL) {
480  /* If we reached the max memcap, we get a used tracker */
481  if (!(DEFRAG_CHECK_MEMCAP(sizeof(DefragTracker)))) {
482  /* declare state of emergency */
483  //if (!(SC_ATOMIC_GET(defragtracker_flags) & DEFRAG_EMERGENCY)) {
484  // SC_ATOMIC_OR(defragtracker_flags, DEFRAG_EMERGENCY);
485 
486  /* under high load, waking up the flow mgr each time leads
487  * to high cpu usage. Flows are not timed out much faster if
488  * we check a 1000 times a second. */
489  // FlowWakeupFlowManagerThread();
490  //}
491 
492  dt = DefragTrackerGetUsedDefragTracker();
493  if (dt == NULL) {
494  return NULL;
495  }
496 
497  /* freed a tracker, but it's unlocked */
498  } else {
499  /* now see if we can alloc a new tracker */
500  dt = DefragTrackerAlloc();
501  if (dt == NULL) {
502  return NULL;
503  }
504 
505  /* tracker is initialized but *unlocked* */
506  }
507  } else {
508  /* tracker has been recycled before it went into the spare queue */
509 
510  /* tracker is initialized (recylced) but *unlocked* */
511  }
512 
513  (void) SC_ATOMIC_ADD(defragtracker_counter, 1);
514  SCMutexLock(&dt->lock);
515  return dt;
516 }
517 
518 /* DefragGetTrackerFromHash
519  *
520  * Hash retrieval function for trackers. Looks up the hash bucket containing the
521  * tracker pointer. Then compares the packet with the found tracker to see if it is
522  * the tracker we need. If it isn't, walk the list until the right tracker is found.
523  *
524  * returns a *LOCKED* tracker or NULL
525  */
527 {
528  DefragTracker *dt = NULL;
529 
530  /* get the key to our bucket */
531  uint32_t key = DefragHashGetKey(p);
532  /* get our hash bucket and lock it */
534  DRLOCK_LOCK(hb);
535 
536  /* see if the bucket already has a tracker */
537  if (hb->head == NULL) {
538  dt = DefragTrackerGetNew(p);
539  if (dt == NULL) {
540  DRLOCK_UNLOCK(hb);
541  return NULL;
542  }
543 
544  /* tracker is locked */
545  hb->head = dt;
546  hb->tail = dt;
547 
548  /* got one, now lock, initialize and return */
549  DefragTrackerInit(dt,p);
550 
551  DRLOCK_UNLOCK(hb);
552  return dt;
553  }
554 
555  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
556  dt = hb->head;
557 
558  /* see if this is the tracker we are looking for */
559  if (dt->remove || DefragTrackerCompare(dt, p) == 0) {
560  DefragTracker *pdt = NULL; /* previous tracker */
561 
562  while (dt) {
563  pdt = dt;
564  dt = dt->hnext;
565 
566  if (dt == NULL) {
567  dt = pdt->hnext = DefragTrackerGetNew(p);
568  if (dt == NULL) {
569  DRLOCK_UNLOCK(hb);
570  return NULL;
571  }
572  hb->tail = dt;
573 
574  /* tracker is locked */
575 
576  dt->hprev = pdt;
577 
578  /* initialize and return */
579  DefragTrackerInit(dt,p);
580 
581  DRLOCK_UNLOCK(hb);
582  return dt;
583  }
584 
585  if (DefragTrackerCompare(dt, p) != 0) {
586  /* we found our tracker, lets put it on top of the
587  * hash list -- this rewards active trackers */
588  if (dt->hnext) {
589  dt->hnext->hprev = dt->hprev;
590  }
591  if (dt->hprev) {
592  dt->hprev->hnext = dt->hnext;
593  }
594  if (dt == hb->tail) {
595  hb->tail = dt->hprev;
596  }
597 
598  dt->hnext = hb->head;
599  dt->hprev = NULL;
600  hb->head->hprev = dt;
601  hb->head = dt;
602 
603  /* found our tracker, lock & return */
604  SCMutexLock(&dt->lock);
605  (void) DefragTrackerIncrUsecnt(dt);
606  DRLOCK_UNLOCK(hb);
607  return dt;
608  }
609  }
610  }
611 
612  /* lock & return */
613  SCMutexLock(&dt->lock);
614  (void) DefragTrackerIncrUsecnt(dt);
615  DRLOCK_UNLOCK(hb);
616  return dt;
617 }
618 
619 /** \brief look up a tracker in the hash
620  *
621  * \param a address to look up
622  *
623  * \retval h *LOCKED* tracker or NULL
624  */
626 {
627  DefragTracker *dt = NULL;
628 
629  /* get the key to our bucket */
630  uint32_t key = DefragHashGetKey(p);
631  /* get our hash bucket and lock it */
633  DRLOCK_LOCK(hb);
634 
635  /* see if the bucket already has a tracker */
636  if (hb->head == NULL) {
637  DRLOCK_UNLOCK(hb);
638  return dt;
639  }
640 
641  /* ok, we have a tracker in the bucket. Let's find out if it is our tracker */
642  dt = hb->head;
643 
644  /* see if this is the tracker we are looking for */
645  if (DefragTrackerCompare(dt, p) == 0) {
646  while (dt) {
647  dt = dt->hnext;
648 
649  if (dt == NULL) {
650  DRLOCK_UNLOCK(hb);
651  return dt;
652  }
653 
654  if (DefragTrackerCompare(dt, p) != 0) {
655  /* we found our tracker, lets put it on top of the
656  * hash list -- this rewards active tracker */
657  if (dt->hnext) {
658  dt->hnext->hprev = dt->hprev;
659  }
660  if (dt->hprev) {
661  dt->hprev->hnext = dt->hnext;
662  }
663  if (dt == hb->tail) {
664  hb->tail = dt->hprev;
665  }
666 
667  dt->hnext = hb->head;
668  dt->hprev = NULL;
669  hb->head->hprev = dt;
670  hb->head = dt;
671 
672  /* found our tracker, lock & return */
673  SCMutexLock(&dt->lock);
674  (void) DefragTrackerIncrUsecnt(dt);
675  DRLOCK_UNLOCK(hb);
676  return dt;
677  }
678  }
679  }
680 
681  /* lock & return */
682  SCMutexLock(&dt->lock);
683  (void) DefragTrackerIncrUsecnt(dt);
684  DRLOCK_UNLOCK(hb);
685  return dt;
686 }
687 
688 /** \internal
689  * \brief Get a tracker from the hash directly.
690  *
691  * Called in conditions where the spare queue is empty and memcap is reached.
692  *
693  * Walks the hash until a tracker can be freed. "defragtracker_prune_idx" atomic int makes
694  * sure we don't start at the top each time since that would clear the top of
695  * the hash leading to longer and longer search times under high pressure (observed).
696  *
697  * \retval dt tracker or NULL
698  */
699 static DefragTracker *DefragTrackerGetUsedDefragTracker(void)
700 {
701  uint32_t idx = SC_ATOMIC_GET(defragtracker_prune_idx) % defrag_config.hash_size;
702  uint32_t cnt = defrag_config.hash_size;
703 
704  while (cnt--) {
705  if (++idx >= defrag_config.hash_size)
706  idx = 0;
707 
709 
710  if (DRLOCK_TRYLOCK(hb) != 0)
711  continue;
712 
713  DefragTracker *dt = hb->tail;
714  if (dt == NULL) {
715  DRLOCK_UNLOCK(hb);
716  continue;
717  }
718 
719  if (SCMutexTrylock(&dt->lock) != 0) {
720  DRLOCK_UNLOCK(hb);
721  continue;
722  }
723 
724  /** never prune a tracker that is used by a packets
725  * we are currently processing in one of the threads */
726  if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
727  DRLOCK_UNLOCK(hb);
728  SCMutexUnlock(&dt->lock);
729  continue;
730  }
731 
732  /* remove from the hash */
733  if (dt->hprev != NULL)
734  dt->hprev->hnext = dt->hnext;
735  if (dt->hnext != NULL)
736  dt->hnext->hprev = dt->hprev;
737  if (hb->head == dt)
738  hb->head = dt->hnext;
739  if (hb->tail == dt)
740  hb->tail = dt->hprev;
741 
742  dt->hnext = NULL;
743  dt->hprev = NULL;
744  DRLOCK_UNLOCK(hb);
745 
747 
748  SCMutexUnlock(&dt->lock);
749 
750  (void) SC_ATOMIC_ADD(defragtracker_prune_idx, (defrag_config.hash_size - cnt));
751  return dt;
752  }
753 
754  return NULL;
755 }
756 
757 
#define DRLOCK_DESTROY(fb)
Definition: defrag-hash.h:50
#define SCMutexTrylock(mut)
uint8_t DefragGetOsPolicy(Packet *p)
Get the defrag policy based on the destination address of the packet.
Definition: defrag.c:920
#define COPY_ADDRESS(a, b)
Definition: decode.h:125
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
#define SCLogDebug(...)
Definition: util-debug.h:335
#define DRLOCK_INIT(fb)
Definition: defrag-hash.h:49
#define BUG_ON(x)
void DefragTrackerEnqueue(DefragTrackerQueue *q, DefragTracker *dt)
add a tracker to a queue
Definition: defrag-queue.c:70
int DefragPolicyGetHostTimeout(Packet *p)
Definition: defrag-config.c:91
#define FALSE
DefragTracker * DefragLookupTrackerFromHash(Packet *p)
look up a tracker in the hash
Definition: defrag-hash.c:625
uint8_t af
Definition: defrag.h:97
void DefragTrackerQueueDestroy(DefragTrackerQueue *q)
Destroy a tracker queue.
Definition: defrag-queue.c:59
#define unlikely(expr)
Definition: util-optimize.h:35
uint32_t hash_size
Definition: defrag-hash.h:73
uint64_t DefragTrackerGetMemcap(void)
Return memcap value.
Definition: defrag-hash.c:53
long int RandomGet(void)
Definition: util-random.c:129
#define DefragTrackerIncrUsecnt(dt)
Definition: defrag-hash.c:114
Address src_addr
Definition: defrag.h:104
struct DefragTracker_ * hprev
Definition: defrag.h:117
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:107
Address dst
Definition: decode.h:413
int ByteExtractStringUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:244
DefragTracker * DefragGetTrackerFromHash(Packet *p)
Definition: defrag-hash.c:526
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:124
#define SCMutexLock(mut)
#define PKT_IS_IPV4(p)
Definition: decode.h:251
uint32_t u32[10]
Definition: defrag-hash.c:376
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:331
#define SC_ATOMIC_DESTROY(name)
Destroy the lock used to protect this variable.
Definition: util-atomic.h:97
DefragTracker * tail
Definition: defrag-hash.h:61
uint16_t vlan_id[2]
Definition: decode.h:435
#define DRLOCK_LOCK(fb)
Definition: defrag-hash.h:51
SCMutex lock
Definition: defrag.h:85
DefragTrackerQueue * DefragTrackerQueueInit(DefragTrackerQueue *q)
Definition: defrag-queue.c:34
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:203
uint16_t vlan_id[2]
Definition: defrag-hash.c:374
Address dst_addr
Definition: defrag.h:105
#define SC_ATOMIC_INIT(name)
Initialize the previously declared atomic variable and it&#39;s lock.
Definition: util-atomic.h:81
#define SCCalloc(nm, a)
Definition: util-mem.h:253
#define CMP_DEFRAGTRACKER(d1, d2, id)
Definition: defrag-hash.c:443
#define SCMutexUnlock(mut)
#define DRLOCK_TRYLOCK(fb)
Definition: defrag-hash.h:52
IPV6Hdr * ip6h
Definition: decode.h:502
struct DefragHashKey4_ DefragHashKey4
#define DEFRAG_DEFAULT_HASHSIZE
Definition: defrag-hash.c:155
uint32_t src[4]
Definition: defrag-hash.c:372
uint32_t dst[4]
Definition: defrag-hash.c:372
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:294
uint8_t seen_last
Definition: defrag.h:100
void DefragTrackerMoveToSpare(DefragTracker *h)
Definition: defrag-hash.c:75
uint32_t prealloc
Definition: defrag-hash.h:74
#define IPV6_EXTHDR_GET_FH_ID(p)
Definition: decode-ipv6.h:130
DefragTrackerHashRow * defragtracker_hash
Definition: defrag-hash.h:65
DefragConfig defrag_config
Definition: defrag-hash.h:87
DefragTracker * DefragTrackerDequeue(DefragTrackerQueue *q)
remove a tracker from the queue
Definition: defrag-queue.c:103
struct DefragHashKey6_ DefragHashKey6
DefragTracker * head
Definition: defrag-hash.h:60
#define DEFRAG_DEFAULT_PREALLOC
Definition: defrag-hash.c:157
#define SCMutexInit(mut, mutattrs)
#define DEFRAG_DEFAULT_MEMCAP
Definition: defrag-hash.c:156
void DefragInitConfig(char quiet)
initialize the configuration
Definition: defrag-hash.c:161
uint32_t DefragTrackerSpareQueueGetSize(void)
Definition: defrag-hash.c:70
#define DEFRAG_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition: defrag-hash.h:84
uint32_t host_timeout
Definition: defrag.h:108
int ConfValIsTrue(const char *val)
Check if a value is true.
Definition: conf.c:566
IPV4Hdr * ip4h
Definition: decode.h:500
uint8_t remove
Definition: defrag.h:102
int DefragTrackerSetMemcap(uint64_t size)
Update memcap value.
Definition: defrag-hash.c:38
#define SCMalloc(a)
Definition: util-mem.h:222
#define SC_ATOMIC_SET(name, val)
Set the value for the atomic variable.
Definition: util-atomic.h:207
void DefragTrackerClearMemory(DefragTracker *dt)
Definition: defrag-hash.c:149
void DefragTrackerRelease(DefragTracker *t)
Definition: defrag-hash.c:143
#define SCFree(a)
Definition: util-mem.h:322
uint64_t DefragTrackerGetMemuse(void)
Return memuse value.
Definition: defrag-hash.c:64
uint8_t proto
Definition: defrag.h:93
#define WarnInvalidConfEntry(param_name, format, value)
Generic API that can be used by all to log an invalid conf entry.
Definition: util-misc.h:37
uint32_t DefragTrackerQueueLen(DefragTrackerQueue *q)
Definition: defrag-queue.c:136
void DefragTrackerFreeFrags(DefragTracker *tracker)
Free all frags associated with a tracker.
Definition: defrag.c:152
#define IP_GET_IPPROTO(p)
Definition: decode.h:263
uint8_t policy
Definition: defrag.h:95
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:192
struct DefragTracker_ * hnext
Definition: defrag.h:116
uint32_t u32[4]
Definition: defrag-hash.c:365
struct DefragTrackerHashRow_ DefragTrackerHashRow
#define DRLOCK_UNLOCK(fb)
Definition: defrag-hash.h:53
uint32_t id
Definition: defrag.h:90
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
#define DefragTrackerDecrUsecnt(dt)
Definition: defrag-hash.c:116
#define IPV4_GET_IPID(p)
Definition: decode-ipv4.h:129
void DefragHashShutdown(void)
shutdown the flow engine
Definition: defrag-hash.c:294
uint16_t vlan_id[2]
Definition: defrag-hash.c:363
uint32_t hash_rand
Definition: defrag-hash.h:72
Address src
Definition: decode.h:412
uint16_t vlan_id[2]
Definition: defrag.h:88
#define SCMutexDestroy