suricata
util-thash.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2016 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 /**
19  * \file
20  *
21  * \author Victor Julien <victor@inliniac.net>
22  *
23  */
24 
25 #include "suricata-common.h"
26 #include "conf.h"
27 
28 #include "util-debug.h"
29 #include "util-thash.h"
30 
31 #include "util-random.h"
32 #include "util-misc.h"
33 #include "util-byte.h"
34 
35 #include "util-hash-lookup3.h"
36 #include "util-validate.h"
37 
38 static THashData *THashGetUsed(THashTableContext *ctx);
39 static void THashDataEnqueue (THashDataQueue *q, THashData *h);
40 
42 {
43  THashDataEnqueue(&ctx->spare_q, h);
44  (void) SC_ATOMIC_SUB(ctx->counter, 1);
45 }
46 
47 static THashDataQueue *THashDataQueueInit (THashDataQueue *q)
48 {
49  if (q != NULL) {
50  memset(q, 0, sizeof(THashDataQueue));
51  HQLOCK_INIT(q);
52  }
53  return q;
54 }
55 
57 {
59  if (q == NULL) {
60  SCLogError(SC_ERR_FATAL, "Fatal error encountered in THashDataQueueNew. Exiting...");
61  exit(EXIT_SUCCESS);
62  }
63  q = THashDataQueueInit(q);
64  return q;
65 }
66 
67 /**
68  * \brief Destroy a queue
69  *
70  * \param q the queue to destroy
71  */
72 static void THashDataQueueDestroy (THashDataQueue *q)
73 {
74  HQLOCK_DESTROY(q);
75 }
76 
77 /**
78  * \brief add to queue
79  *
80  * \param q queue
81  * \param h data
82  */
83 static void THashDataEnqueue (THashDataQueue *q, THashData *h)
84 {
85 #ifdef DEBUG
86  BUG_ON(q == NULL || h == NULL);
87 #endif
88 
89  HQLOCK_LOCK(q);
90 
91  /* more data in queue */
92  if (q->top != NULL) {
93  h->next = q->top;
94  q->top->prev = h;
95  q->top = h;
96  /* only data */
97  } else {
98  q->top = h;
99  q->bot = h;
100  }
101  q->len++;
102 #ifdef DBG_PERF
103  if (q->len > q->dbg_maxlen)
104  q->dbg_maxlen = q->len;
105 #endif /* DBG_PERF */
106  HQLOCK_UNLOCK(q);
107 }
108 
109 /**
110  * \brief remove data from the queue
111  *
112  * \param q queue
113  *
114  * \retval h data or NULL if empty list.
115  */
116 static THashData *THashDataDequeue (THashDataQueue *q)
117 {
118  HQLOCK_LOCK(q);
119 
120  THashData *h = q->bot;
121  if (h == NULL) {
122  HQLOCK_UNLOCK(q);
123  return NULL;
124  }
125 
126  /* more packets in queue */
127  if (q->bot->prev != NULL) {
128  q->bot = q->bot->prev;
129  q->bot->next = NULL;
130  /* just the one we remove, so now empty */
131  } else {
132  q->top = NULL;
133  q->bot = NULL;
134  }
135 
136 #ifdef DEBUG
137  BUG_ON(q->len == 0);
138 #endif
139  if (q->len > 0)
140  q->len--;
141 
142  h->next = NULL;
143  h->prev = NULL;
144 
145  HQLOCK_UNLOCK(q);
146  return h;
147 }
148 
149 #if 0
150 static uint32_t THashDataQueueLen(THashDataQueue *q)
151 {
152  uint32_t len;
153  HQLOCK_LOCK(q);
154  len = q->len;
155  HQLOCK_UNLOCK(q);
156  return len;
157 }
158 #endif
159 
160 static THashData *THashDataAlloc(THashTableContext *ctx)
161 {
162  const size_t data_size = THASH_DATA_SIZE(ctx);
163 
164  if (!(THASH_CHECK_MEMCAP(ctx, data_size))) {
165  return NULL;
166  }
167 
168  (void) SC_ATOMIC_ADD(ctx->memuse, data_size);
169 
170  THashData *h = SCCalloc(1, data_size);
171  if (unlikely(h == NULL))
172  goto error;
173 
174  /* points to data right after THashData block */
175  h->data = (uint8_t *)h + sizeof(THashData);
176 
177 // memset(h, 0x00, data_size);
178 
179  SCMutexInit(&h->m, NULL);
180  SC_ATOMIC_INIT(h->use_cnt);
181  return h;
182 
183 error:
184  return NULL;
185 }
186 
187 static void THashDataFree(THashTableContext *ctx, THashData *h)
188 {
189  if (h != NULL) {
190  DEBUG_VALIDATE_BUG_ON(SC_ATOMIC_GET(h->use_cnt) != 0);
191 
192  if (h->data != NULL) {
193  ctx->config.DataFree(h->data);
194  }
195  SCMutexDestroy(&h->m);
196  SCFree(h);
197  (void) SC_ATOMIC_SUB(ctx->memuse, THASH_DATA_SIZE(ctx));
198  }
199 }
200 
201 #define THASH_DEFAULT_HASHSIZE 4096
202 #define THASH_DEFAULT_MEMCAP 16777216
203 #define THASH_DEFAULT_PREALLOC 1000
204 
205 #define GET_VAR(prefix,name) \
206  snprintf(varname, sizeof(varname), "%s.%s", (prefix), (name))
207 
208 /** \brief initialize the configuration
209  * \warning Not thread safe */
210 static int THashInitConfig(THashTableContext *ctx, const char *cnf_prefix)
211 {
212  char varname[256];
213 
214  SCLogDebug("initializing thash engine...");
215 
216  /* Check if we have memcap and hash_size defined at config */
217  const char *conf_val;
218  uint32_t configval = 0;
219 
220  /** set config values for memcap, prealloc and hash_size */
221  GET_VAR(cnf_prefix, "memcap");
222  if ((ConfGet(varname, &conf_val)) == 1)
223  {
224  if (ParseSizeStringU64(conf_val, &ctx->config.memcap) < 0) {
225  SCLogError(SC_ERR_SIZE_PARSE, "Error parsing %s "
226  "from conf file - %s. Killing engine",
227  varname, conf_val);
228  return -1;
229  }
230  }
231  GET_VAR(cnf_prefix, "hash-size");
232  if ((ConfGet(varname, &conf_val)) == 1)
233  {
234  if (StringParseUint32(&configval, 10, strlen(conf_val),
235  conf_val) > 0) {
236  ctx->config.hash_size = configval;
237  }
238  }
239 
240  GET_VAR(cnf_prefix, "prealloc");
241  if ((ConfGet(varname, &conf_val)) == 1)
242  {
243  if (StringParseUint32(&configval, 10, strlen(conf_val),
244  conf_val) > 0) {
245  ctx->config.prealloc = configval;
246  } else {
247  WarnInvalidConfEntry(varname, "%"PRIu32, ctx->config.prealloc);
248  }
249  }
250 
251  /* alloc hash memory */
252  uint64_t hash_size = ctx->config.hash_size * sizeof(THashHashRow);
253  if (!(THASH_CHECK_MEMCAP(ctx, hash_size))) {
254  SCLogError(SC_ERR_THASH_INIT, "allocating hash failed: "
255  "max hash memcap is smaller than projected hash size. "
256  "Memcap: %"PRIu64", Hash table size %"PRIu64". Calculate "
257  "total hash size by multiplying \"hash-size\" with %"PRIuMAX", "
258  "which is the hash bucket size.", ctx->config.memcap, hash_size,
259  (uintmax_t)sizeof(THashHashRow));
260  return -1;
261  }
262  ctx->array = SCMallocAligned(ctx->config.hash_size * sizeof(THashHashRow), CLS);
263  if (unlikely(ctx->array == NULL)) {
264  SCLogError(SC_ERR_THASH_INIT, "Fatal error encountered in THashInitConfig. Exiting...");
265  return -1;
266  }
267  memset(ctx->array, 0, ctx->config.hash_size * sizeof(THashHashRow));
268 
269  uint32_t i = 0;
270  for (i = 0; i < ctx->config.hash_size; i++) {
271  HRLOCK_INIT(&ctx->array[i]);
272  }
273  (void) SC_ATOMIC_ADD(ctx->memuse, (ctx->config.hash_size * sizeof(THashHashRow)));
274 
275  /* pre allocate prealloc */
276  for (i = 0; i < ctx->config.prealloc; i++) {
277  if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) {
278  SCLogError(SC_ERR_THASH_INIT, "preallocating data failed: "
279  "max thash memcap reached. Memcap %"PRIu64", "
280  "Memuse %"PRIu64".", ctx->config.memcap,
281  ((uint64_t)SC_ATOMIC_GET(ctx->memuse) + THASH_DATA_SIZE(ctx)));
282  return -1;
283  }
284 
285  THashData *h = THashDataAlloc(ctx);
286  if (h == NULL) {
287  SCLogError(SC_ERR_THASH_INIT, "preallocating data failed: %s", strerror(errno));
288  return -1;
289  }
290  THashDataEnqueue(&ctx->spare_q,h);
291  }
292 
293  return 0;
294 }
295 
296 THashTableContext *THashInit(const char *cnf_prefix, size_t data_size,
297  int (*DataSet)(void *, void *), void (*DataFree)(void *), uint32_t (*DataHash)(void *),
298  bool (*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
299 {
300  THashTableContext *ctx = SCCalloc(1, sizeof(*ctx));
301  BUG_ON(!ctx);
302 
303  ctx->config.data_size = data_size;
304  ctx->config.DataSet = DataSet;
305  ctx->config.DataFree = DataFree;
306  ctx->config.DataHash = DataHash;
307  ctx->config.DataCompare = DataCompare;
308 
309  /* set defaults */
310  ctx->config.hash_rand = (uint32_t)RandomGet();
312  /* Reset memcap in case of loading from file to the highest possible value
313  unless defined by the rule keyword */
314 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
315  // limit memcap size to default when fuzzing
317 #else
318  if (memcap > 0) {
319  ctx->config.memcap = memcap;
320  } else {
321  ctx->config.memcap = reset_memcap ? UINT64_MAX : THASH_DEFAULT_MEMCAP;
322  }
323 #endif
325 
326  SC_ATOMIC_INIT(ctx->counter);
327  SC_ATOMIC_INIT(ctx->memuse);
328  SC_ATOMIC_INIT(ctx->prune_idx);
329  THashDataQueueInit(&ctx->spare_q);
330 
331  if (THashInitConfig(ctx, cnf_prefix) < 0) {
332  THashShutdown(ctx);
333  ctx = NULL;
334  }
335  return ctx;
336 }
337 
338 /* \brief Set memcap to current memuse
339  * */
341 {
342  ctx->config.memcap = MAX(SC_ATOMIC_GET(ctx->memuse), ctx->config.memcap);
343  SCLogDebug("memcap after load set to: %" PRIu64, ctx->config.memcap);
344 }
345 
346 /** \brief shutdown the flow engine
347  * \warning Not thread safe */
349 {
350  THashData *h;
351  uint32_t u;
352 
353  /* free spare queue */
354  while ((h = THashDataDequeue(&ctx->spare_q))) {
355  BUG_ON(SC_ATOMIC_GET(h->use_cnt) > 0);
356  THashDataFree(ctx, h);
357  }
358 
359  /* clear and free the hash */
360  if (ctx->array != NULL) {
361  for (u = 0; u < ctx->config.hash_size; u++) {
362  h = ctx->array[u].head;
363  while (h) {
364  THashData *n = h->next;
365  THashDataFree(ctx, h);
366  h = n;
367  }
368 
369  HRLOCK_DESTROY(&ctx->array[u]);
370  }
371  SCFreeAligned(ctx->array);
372  ctx->array = NULL;
373  }
374  (void) SC_ATOMIC_SUB(ctx->memuse, ctx->config.hash_size * sizeof(THashHashRow));
375  THashDataQueueDestroy(&ctx->spare_q);
376  SCFree(ctx);
377  return;
378 }
379 
380 /** \brief Walk the hash
381  *
382  */
383 int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, void *output_ctx)
384 {
385  uint32_t u;
386 
387  if (ctx->array == NULL)
388  return -1;
389 
390  bool err = false;
391  for (u = 0; u < ctx->config.hash_size; u++) {
392  THashHashRow *hb = &ctx->array[u];
393  HRLOCK_LOCK(hb);
394  THashData *h = hb->head;
395  while (h) {
396  char output_string[1024] = "";
397  int size = FormatterFunc(h->data, output_string, sizeof(output_string));
398  if (size > 0) {
399  if (OutputterFunc(output_ctx, (const uint8_t *)output_string, size) < 0) {
400  err = true;
401  break;
402  }
403  }
404  h = h->next;
405  }
406  HRLOCK_UNLOCK(hb);
407  if (err == true)
408  return -1;
409  }
410  return 0;
411 }
412 
413 /** \brief Cleanup the thash engine
414  *
415  * Cleanup the thash engine from tag and threshold.
416  *
417  */
419 {
420  uint32_t u;
421 
422  if (ctx->array == NULL)
423  return;
424 
425  for (u = 0; u < ctx->config.hash_size; u++) {
426  THashHashRow *hb = &ctx->array[u];
427  HRLOCK_LOCK(hb);
428  THashData *h = hb->head;
429  while (h) {
430  if ((SC_ATOMIC_GET(h->use_cnt) > 0)) {
431  h = h->next;
432  } else {
433  THashData *n = h->next;
434  /* remove from the hash */
435  if (h->prev != NULL)
436  h->prev->next = h->next;
437  if (h->next != NULL)
438  h->next->prev = h->prev;
439  if (hb->head == h)
440  hb->head = h->next;
441  if (hb->tail == h)
442  hb->tail = h->prev;
443  h->next = NULL;
444  h->prev = NULL;
445  THashDataMoveToSpare(ctx, h);
446  h = n;
447  }
448  }
449  HRLOCK_UNLOCK(hb);
450  }
451  return;
452 }
453 
454 /* calculate the hash key for this packet
455  *
456  * we're using:
457  * hash_rand -- set at init time
458  * source address
459  */
460 static uint32_t THashGetKey(const THashConfig *cnf, void *data)
461 {
462  uint32_t key;
463 
464  key = cnf->DataHash(data);
465  key %= cnf->hash_size;
466 
467  return key;
468 }
469 
470 static inline int THashCompare(const THashConfig *cnf, void *a, void *b)
471 {
472  if (cnf->DataCompare(a, b))
473  return 1;
474  return 0;
475 }
476 
477 /**
478  * \brief Get new data
479  *
480  * Get new data. We're checking memcap first and will try to make room
481  * if the memcap is reached.
482  *
483  * \retval h *LOCKED* data on succes, NULL on error.
484  */
485 static THashData *THashDataGetNew(THashTableContext *ctx, void *data)
486 {
487  THashData *h = NULL;
488 
489  /* get data from the spare queue */
490  h = THashDataDequeue(&ctx->spare_q);
491  if (h == NULL) {
492  /* If we reached the max memcap, we get used data */
493  if (!(THASH_CHECK_MEMCAP(ctx, THASH_DATA_SIZE(ctx)))) {
494  h = THashGetUsed(ctx);
495  if (h == NULL) {
496  return NULL;
497  }
498 
499  if (!SC_ATOMIC_GET(ctx->memcap_reached)) {
500  SC_ATOMIC_SET(ctx->memcap_reached, true);
501  }
502 
503  /* freed data, but it's unlocked */
504  } else {
505  /* now see if we can alloc a new data */
506  h = THashDataAlloc(ctx);
507  if (h == NULL) {
508  return NULL;
509  }
510 
511  /* data is initialized but *unlocked* */
512  }
513  } else {
514  /* data has been recycled before it went into the spare queue */
515 
516  /* data is initialized (recylced) but *unlocked* */
517  }
518 
519  // setup the data
520  BUG_ON(ctx->config.DataSet(h->data, data) != 0);
521 
522  (void) SC_ATOMIC_ADD(ctx->counter, 1);
523  SCMutexLock(&h->m);
524  return h;
525 }
526 
527 /*
528  * returns a *LOCKED* data or NULL
529  */
530 
531 struct THashDataGetResult
533 {
534  struct THashDataGetResult res = { .data = NULL, .is_new = false, };
535  THashData *h = NULL;
536 
537  /* get the key to our bucket */
538  uint32_t key = THashGetKey(&ctx->config, data);
539  /* get our hash bucket and lock it */
540  THashHashRow *hb = &ctx->array[key];
541  HRLOCK_LOCK(hb);
542 
543  /* see if the bucket already has data */
544  if (hb->head == NULL) {
545  h = THashDataGetNew(ctx, data);
546  if (h == NULL) {
547  HRLOCK_UNLOCK(hb);
548  return res;
549  }
550 
551  /* data is locked */
552  hb->head = h;
553  hb->tail = h;
554 
555  /* initialize and return */
556  (void) THashIncrUsecnt(h);
557 
558  HRLOCK_UNLOCK(hb);
559  res.data = h;
560  res.is_new = true;
561  return res;
562  }
563 
564  /* ok, we have data in the bucket. Let's find out if it is our data */
565  h = hb->head;
566 
567  /* see if this is the data we are looking for */
568  if (THashCompare(&ctx->config, h->data, data) == 0) {
569  THashData *ph = NULL; /* previous data */
570 
571  while (h) {
572  ph = h;
573  h = h->next;
574 
575  if (h == NULL) {
576  h = ph->next = THashDataGetNew(ctx, data);
577  if (h == NULL) {
578  HRLOCK_UNLOCK(hb);
579  return res;
580  }
581  hb->tail = h;
582 
583  /* data is locked */
584 
585  h->prev = ph;
586 
587  /* initialize and return */
588  (void) THashIncrUsecnt(h);
589 
590  HRLOCK_UNLOCK(hb);
591  res.data = h;
592  res.is_new = true;
593  return res;
594  }
595 
596  if (THashCompare(&ctx->config, h->data, data) != 0) {
597  /* we found our data, lets put it on top of the
598  * hash list -- this rewards active data */
599  if (h->next) {
600  h->next->prev = h->prev;
601  }
602  if (h->prev) {
603  h->prev->next = h->next;
604  }
605  if (h == hb->tail) {
606  hb->tail = h->prev;
607  }
608 
609  h->next = hb->head;
610  h->prev = NULL;
611  hb->head->prev = h;
612  hb->head = h;
613 
614  /* found our data, lock & return */
615  SCMutexLock(&h->m);
616  (void) THashIncrUsecnt(h);
617  HRLOCK_UNLOCK(hb);
618  res.data = h;
619  res.is_new = false;
620  /* coverity[missing_unlock : FALSE] */
621  return res;
622  }
623  }
624  }
625 
626  /* lock & return */
627  SCMutexLock(&h->m);
628  (void) THashIncrUsecnt(h);
629  HRLOCK_UNLOCK(hb);
630  res.data = h;
631  res.is_new = false;
632  /* coverity[missing_unlock : FALSE] */
633  return res;
634 }
635 
636 /** \brief look up data in the hash
637  *
638  * \param data data to look up
639  *
640  * \retval h *LOCKED* data or NULL
641  */
643 {
644  THashData *h = NULL;
645 
646  /* get the key to our bucket */
647  uint32_t key = THashGetKey(&ctx->config, data);
648  /* get our hash bucket and lock it */
649  THashHashRow *hb = &ctx->array[key];
650  HRLOCK_LOCK(hb);
651 
652  if (hb->head == NULL) {
653  HRLOCK_UNLOCK(hb);
654  return h;
655  }
656 
657  /* ok, we have data in the bucket. Let's find out if it is our data */
658  h = hb->head;
659 
660  /* see if this is the data we are looking for */
661  if (THashCompare(&ctx->config, h->data, data) == 0) {
662  while (h) {
663  h = h->next;
664  if (h == NULL) {
665  HRLOCK_UNLOCK(hb);
666  return h;
667  }
668 
669  if (THashCompare(&ctx->config, h->data, data) != 0) {
670  /* we found our data, lets put it on top of the
671  * hash list -- this rewards active data */
672  if (h->next) {
673  h->next->prev = h->prev;
674  }
675  if (h->prev) {
676  h->prev->next = h->next;
677  }
678  if (h == hb->tail) {
679  hb->tail = h->prev;
680  }
681 
682  h->next = hb->head;
683  h->prev = NULL;
684  hb->head->prev = h;
685  hb->head = h;
686 
687  /* found our data, lock & return */
688  SCMutexLock(&h->m);
689  (void) THashIncrUsecnt(h);
690  HRLOCK_UNLOCK(hb);
691  return h;
692  }
693  }
694  }
695 
696  /* lock & return */
697  SCMutexLock(&h->m);
698  (void) THashIncrUsecnt(h);
699  HRLOCK_UNLOCK(hb);
700  return h;
701 }
702 
703 /** \internal
704  * \brief Get data from the hash directly.
705  *
706  * Called in conditions where the spare queue is empty and memcap is
707  * reached.
708  *
709  * Walks the hash until data can be freed. "prune_idx" atomic int makes
710  * sure we don't start at the top each time since that would clear the top
711  * of the hash leading to longer and longer search times under high
712  * pressure (observed).
713  *
714  * \retval h data or NULL
715  */
716 static THashData *THashGetUsed(THashTableContext *ctx)
717 {
718  uint32_t idx = SC_ATOMIC_GET(ctx->prune_idx) % ctx->config.hash_size;
719  uint32_t cnt = ctx->config.hash_size;
720 
721  while (cnt--) {
722  if (++idx >= ctx->config.hash_size)
723  idx = 0;
724 
725  THashHashRow *hb = &ctx->array[idx];
726 
727  if (HRLOCK_TRYLOCK(hb) != 0)
728  continue;
729 
730  THashData *h = hb->tail;
731  if (h == NULL) {
732  HRLOCK_UNLOCK(hb);
733  continue;
734  }
735 
736  if (SCMutexTrylock(&h->m) != 0) {
737  HRLOCK_UNLOCK(hb);
738  continue;
739  }
740 
741  if (SC_ATOMIC_GET(h->use_cnt) > 0) {
742  HRLOCK_UNLOCK(hb);
743  SCMutexUnlock(&h->m);
744  continue;
745  }
746 
747  /* remove from the hash */
748  if (h->prev != NULL)
749  h->prev->next = h->next;
750  if (h->next != NULL)
751  h->next->prev = h->prev;
752  if (hb->head == h)
753  hb->head = h->next;
754  if (hb->tail == h)
755  hb->tail = h->prev;
756 
757  h->next = NULL;
758  h->prev = NULL;
759  HRLOCK_UNLOCK(hb);
760 
761  if (h->data != NULL) {
762  ctx->config.DataFree(h->data);
763  }
764  SCMutexUnlock(&h->m);
765 
766  (void) SC_ATOMIC_ADD(ctx->prune_idx, (ctx->config.hash_size - cnt));
767  return h;
768  }
769 
770  return NULL;
771 }
772 
773 /**
774  * \retval int -1 not found
775  * \retval int 0 found, but it was busy (ref cnt)
776  * \retval int 1 found and removed */
778 {
779  /* get the key to our bucket */
780  uint32_t key = THashGetKey(&ctx->config, data);
781  /* get our hash bucket and lock it */
782  THashHashRow *hb = &ctx->array[key];
783 
784  HRLOCK_LOCK(hb);
785  THashData *h = hb->head;
786  while (h != NULL) {
787  /* see if this is the data we are looking for */
788  if (THashCompare(&ctx->config, h->data, data) == 0) {
789  h = h->next;
790  continue;
791  }
792 
793  SCMutexLock(&h->m);
794  if (SC_ATOMIC_GET(h->use_cnt) > 0) {
795  SCMutexUnlock(&h->m);
796  HRLOCK_UNLOCK(hb);
797  return 0;
798  }
799 
800  /* remove from the hash */
801  if (h->prev != NULL)
802  h->prev->next = h->next;
803  if (h->next != NULL)
804  h->next->prev = h->prev;
805  if (hb->head == h)
806  hb->head = h->next;
807  if (hb->tail == h)
808  hb->tail = h->prev;
809 
810  h->next = NULL;
811  h->prev = NULL;
812  SCMutexUnlock(&h->m);
813  HRLOCK_UNLOCK(hb);
814  THashDataFree(ctx, h);
815  SCLogDebug("found and removed");
816  return 1;
817  }
818 
819  HRLOCK_UNLOCK(hb);
820  SCLogDebug("data not found");
821  return -1;
822 }
HRLOCK_DESTROY
#define HRLOCK_DESTROY(fb)
Definition: host.h:50
util-byte.h
HQLOCK_LOCK
#define HQLOCK_LOCK(q)
Definition: host-queue.h:67
len
uint8_t len
Definition: app-layer-dnp3.h:2
THashCleanup
void THashCleanup(THashTableContext *ctx)
Cleanup the thash engine.
Definition: util-thash.c:418
THashDataGetResult::data
THashData * data
Definition: util-thash.h:206
SC_ATOMIC_INIT
#define SC_ATOMIC_INIT(name)
wrapper for initializing an atomic variable.
Definition: util-atomic.h:315
CLS
#define CLS
Definition: suricata-common.h:45
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:387
HQLOCK_DESTROY
#define HQLOCK_DESTROY(q)
Definition: host-queue.h:66
THashOutputFunc
int(* THashOutputFunc)(void *output_ctx, const uint8_t *data, const uint32_t data_len)
Definition: util-thash.h:125
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
ParseSizeStringU64
int ParseSizeStringU64(const char *size, uint64_t *res)
Definition: util-misc.c:200
THashData_::prev
struct THashData_ * prev
Definition: util-thash.h:96
THashDataConfig_::DataFree
void(* DataFree)(void *)
Definition: util-thash.h:136
THashRemoveFromHash
int THashRemoveFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:777
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
THashData_::next
struct THashData_ * next
Definition: util-thash.h:95
THashConsolidateMemcap
void THashConsolidateMemcap(THashTableContext *ctx)
Definition: util-thash.c:340
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
THashDataQueue_
Definition: util-thash.h:106
THashDataConfig_::DataHash
uint32_t(* DataHash)(void *)
Definition: util-thash.h:137
RandomGet
long int RandomGet(void)
Definition: util-random.c:129
THashDataConfig_::DataCompare
bool(* DataCompare)(void *, void *)
Definition: util-thash.h:138
MAX
#define MAX(x, y)
Definition: suricata-common.h:376
hashsize
#define hashsize(n)
Definition: util-hash-lookup3.c:67
THashDataConfig_::DataSet
int(* DataSet)(void *dst, void *src)
Definition: util-thash.h:135
HRLOCK_LOCK
#define HRLOCK_LOCK(fb)
Definition: host.h:51
SC_ERR_SIZE_PARSE
@ SC_ERR_SIZE_PARSE
Definition: util-error.h:230
ConfGet
int ConfGet(const char *name, const char **vptr)
Retrieve the value of a configuration node.
Definition: conf.c:330
HRLOCK_UNLOCK
#define HRLOCK_UNLOCK(fb)
Definition: host.h:53
THashDataConfig_::prealloc
uint32_t prealloc
Definition: util-thash.h:132
THashDataConfig_::hash_size
uint32_t hash_size
Definition: util-thash.h:131
util-debug.h
THASH_DEFAULT_HASHSIZE
#define THASH_DEFAULT_HASHSIZE
Definition: util-thash.c:201
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
THashTableContext_
Definition: util-thash.h:143
res
PoolThreadReserved res
Definition: stream-tcp-private.h:0
THASH_DATA_SIZE
#define THASH_DATA_SIZE(ctx)
Definition: util-thash.h:141
THashDataQueue_::bot
THashData * bot
Definition: util-thash.h:108
THashData_::m
SCMutex m
Definition: util-thash.h:88
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:281
THashInit
THashTableContext * THashInit(const char *cnf_prefix, size_t data_size, int(*DataSet)(void *, void *), void(*DataFree)(void *), uint32_t(*DataHash)(void *), bool(*DataCompare)(void *, void *), bool reset_memcap, uint64_t memcap, uint32_t hashsize)
Definition: util-thash.c:296
THashTableContext_::array
THashHashRow * array
Definition: util-thash.h:145
SC_ATOMIC_SUB
#define SC_ATOMIC_SUB(name, val)
sub a value from our atomic variable
Definition: util-atomic.h:342
THashDataGetResult
Definition: util-thash.h:205
THashDataConfig_::memcap
uint64_t memcap
Definition: util-thash.h:129
SCFreeAligned
#define SCFreeAligned(p)
Definition: util-mem.h:77
GET_VAR
#define GET_VAR(prefix, name)
Definition: util-thash.c:205
conf.h
HRLOCK_INIT
#define HRLOCK_INIT(fb)
Definition: host.h:49
THashDataMoveToSpare
void THashDataMoveToSpare(THashTableContext *ctx, THashData *h)
Definition: util-thash.c:41
THashTableContext_::spare_q
THashDataQueue spare_q
Definition: util-thash.h:151
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:37
THashShutdown
void THashShutdown(THashTableContext *ctx)
shutdown the flow engine
Definition: util-thash.c:348
HQLOCK_UNLOCK
#define HQLOCK_UNLOCK(q)
Definition: host-queue.h:69
StringParseUint32
int StringParseUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:313
THashData_::data
void * data
Definition: util-thash.h:93
THashData_
Definition: util-thash.h:86
THashDataQueue_::len
uint32_t len
Definition: util-thash.h:109
suricata-common.h
THASH_DEFAULT_MEMCAP
#define THASH_DEFAULT_MEMCAP
Definition: util-thash.c:202
SCMallocAligned
#define SCMallocAligned(size, align)
Definition: util-mem.h:68
HQLOCK_INIT
#define HQLOCK_INIT(q)
Definition: host-queue.h:65
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
THashGetFromHash
struct THashDataGetResult THashGetFromHash(THashTableContext *ctx, void *data)
Definition: util-thash.c:532
THashLookupFromHash
THashData * THashLookupFromHash(THashTableContext *ctx, void *data)
look up data in the hash
Definition: util-thash.c:642
util-hash-lookup3.h
SC_ERR_THASH_INIT
@ SC_ERR_THASH_INIT
Definition: util-error.h:354
THASH_DEFAULT_PREALLOC
#define THASH_DEFAULT_PREALLOC
Definition: util-thash.c:203
util-validate.h
SCMalloc
#define SCMalloc(sz)
Definition: util-mem.h:47
THashDataConfig_
Definition: util-thash.h:128
THashWalk
int THashWalk(THashTableContext *ctx, THashFormatFunc FormatterFunc, THashOutputFunc OutputterFunc, void *output_ctx)
Walk the hash.
Definition: util-thash.c:383
SCFree
#define SCFree(p)
Definition: util-mem.h:61
SC_ERR_FATAL
@ SC_ERR_FATAL
Definition: util-error.h:203
THashFormatFunc
int(* THashFormatFunc)(const void *in_data, char *output, size_t output_size)
Definition: util-thash.h:126
util-random.h
HRLOCK_TRYLOCK
#define HRLOCK_TRYLOCK(fb)
Definition: host.h:52
THashDataConfig_::data_size
uint32_t data_size
Definition: util-thash.h:134
THashDataConfig_::hash_rand
uint32_t hash_rand
Definition: util-thash.h:130
THashIncrUsecnt
#define THashIncrUsecnt(h)
Definition: util-thash.h:169
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
util-misc.h
util-thash.h
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMutexDestroy
#define SCMutexDestroy
Definition: threads-debug.h:120
THASH_CHECK_MEMCAP
#define THASH_CHECK_MEMCAP(ctx, size)
check if a memory alloc would fit in the memcap
Definition: util-thash.h:166
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111
THashDataQueueNew
THashDataQueue * THashDataQueueNew(void)
Definition: util-thash.c:56
SCMutexTrylock
#define SCMutexTrylock(mut)
Definition: threads-debug.h:118
THashDataQueue_::top
THashData * top
Definition: util-thash.h:107
THashTableContext_::config
THashConfig config
Definition: util-thash.h:153