suricata
flow-spare-pool.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2020 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  * Flow queue handler functions
24  */
25 
26 #include "suricata-common.h"
27 #include "threads.h"
28 #include "flow-private.h"
29 #include "flow-queue.h"
30 #include "flow-util.h"
31 #include "flow-spare-pool.h"
32 #include "util-error.h"
33 #include "util-debug.h"
34 #include "util-print.h"
35 #include "util-validate.h"
36 
37 typedef struct FlowSparePool {
41 
42 static uint32_t flow_spare_pool_flow_cnt = 0;
43 static uint32_t flow_spare_pool_block_size = 100;
44 static FlowSparePool *flow_spare_pool = NULL;
45 static SCMutex flow_spare_pool_m = SCMUTEX_INITIALIZER;
46 
47 uint32_t FlowSpareGetPoolSize(void)
48 {
49  uint32_t size;
50  SCMutexLock(&flow_spare_pool_m);
51  size = flow_spare_pool_flow_cnt;
52  SCMutexUnlock(&flow_spare_pool_m);
53  return size;
54 }
55 
56 static FlowSparePool *FlowSpareGetPool(void)
57 {
58  FlowSparePool *p = SCCalloc(1, sizeof(*p));
59  if (p == NULL)
60  return NULL;
61  return p;
62 }
63 
64 static bool FlowSparePoolUpdateBlock(FlowSparePool *p)
65 {
66  DEBUG_VALIDATE_BUG_ON(p == NULL);
67 
68  for (uint32_t i = p->queue.len; i < flow_spare_pool_block_size; i++)
69  {
70  Flow *f = FlowAlloc();
71  if (f == NULL)
72  return false;
74  }
75  return true;
76 }
77 
78 #ifdef FSP_VALIDATE
79 static void Validate(FlowSparePool *top, const uint32_t target)
80 {
81  if (top == NULL) {
82  assert(target == 0);
83  return;
84  }
85 
86  assert(top->queue.len >= 1);
87  //if (top->next != NULL)
88  // assert(top->next->queue.len == flow_spare_pool_block_size);
89 
90  uint32_t cnt = 0;
91  for (FlowSparePool *p = top; p != NULL; p = p->next)
92  {
93  assert(p->queue.len);
94  cnt += p->queue.len;
95  }
96  assert(cnt == target);
97 }
98 #endif
99 
101 {
102  SCMutexLock(&flow_spare_pool_m);
103  if (flow_spare_pool == NULL) {
104  flow_spare_pool = FlowSpareGetPool();
105  }
106  DEBUG_VALIDATE_BUG_ON(flow_spare_pool == NULL);
107 
108  /* if the top is full, get a new block */
109  if (flow_spare_pool->queue.len >= flow_spare_pool_block_size) {
110  FlowSparePool *p = FlowSpareGetPool();
111  DEBUG_VALIDATE_BUG_ON(p == NULL);
112  p->next = flow_spare_pool;
113  flow_spare_pool = p;
114  }
115  /* add to the (possibly new) top */
116  FlowQueuePrivateAppendFlow(&flow_spare_pool->queue, f);
117  flow_spare_pool_flow_cnt++;
118 
119  SCMutexUnlock(&flow_spare_pool_m);
120 }
121 
123 {
124 
125 }
126 
128 {
129  SCMutexLock(&flow_spare_pool_m);
130  if (flow_spare_pool == NULL || flow_spare_pool_flow_cnt == 0) {
131  SCMutexUnlock(&flow_spare_pool_m);
132  FlowQueuePrivate empty = { NULL, NULL, 0 };
133  return empty;
134  }
135 
136  /* top if full or its the only block we have */
137  if (flow_spare_pool->queue.len >= flow_spare_pool_block_size || flow_spare_pool->next == NULL) {
138  FlowSparePool *p = flow_spare_pool;
139  flow_spare_pool = p->next;
140  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
141  flow_spare_pool_flow_cnt -= p->queue.len;
142 #ifdef FSP_VALIDATE
143  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
144 #endif
145  SCMutexUnlock(&flow_spare_pool_m);
146 
147  FlowQueuePrivate ret = p->queue;
148  SCFree(p);
149  return ret;
150  /* next should always be full if it exists */
151  } else if (flow_spare_pool->next != NULL) {
152  FlowSparePool *p = flow_spare_pool->next;
153  flow_spare_pool->next = p->next;
154  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
155  flow_spare_pool_flow_cnt -= p->queue.len;
156 #ifdef FSP_VALIDATE
157  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
158 #endif
159  SCMutexUnlock(&flow_spare_pool_m);
160 
161  FlowQueuePrivate ret = p->queue;
162  SCFree(p);
163  return ret;
164  }
165 
166  SCMutexUnlock(&flow_spare_pool_m);
167  FlowQueuePrivate empty = { NULL, NULL, 0 };
168  return empty;
169 }
170 
171 void FlowSparePoolUpdate(uint32_t size)
172 {
173  const int64_t todo = (int64_t)flow_config.prealloc - (int64_t)size;
174  if (todo < 0) {
175  uint32_t to_remove = (uint32_t)(todo * -1) / 10;
176  while (to_remove) {
177  if (to_remove < flow_spare_pool_block_size)
178  return;
179 
180  FlowSparePool *p = NULL;
181  SCMutexLock(&flow_spare_pool_m);
182  p = flow_spare_pool;
183  if (p != NULL) {
184  flow_spare_pool = p->next;
185  flow_spare_pool_flow_cnt -= p->queue.len;
186  to_remove -= p->queue.len;
187  }
188  SCMutexUnlock(&flow_spare_pool_m);
189 
190  if (p != NULL) {
191  Flow *f;
192  while ((f = FlowQueuePrivateGetFromTop(&p->queue))) {
193  FlowFree(f);
194  }
195  SCFree(p);
196  }
197  }
198  } else if (todo > 0) {
199  FlowSparePool *head = NULL, *tail = NULL;
200 
201  uint32_t blocks = ((uint32_t)todo / flow_spare_pool_block_size) + 1;
202 
203  uint32_t flow_cnt = 0;
204  for (uint32_t cnt = 0; cnt < blocks; cnt++) {
205  FlowSparePool *p = FlowSpareGetPool();
206  if (p == NULL) {
207  break;
208  }
209  const bool ok = FlowSparePoolUpdateBlock(p);
210  if (p->queue.len == 0) {
211  SCFree(p);
212  break;
213  }
214  flow_cnt += p->queue.len;
215 
216  /* prepend to list */
217  p->next = head;
218  head = p;
219  if (tail == NULL)
220  tail = p;
221  if (!ok)
222  break;
223  }
224  if (head) {
225  SCMutexLock(&flow_spare_pool_m);
226  if (flow_spare_pool == NULL) {
227  flow_spare_pool = head;
228  } else if (tail != NULL) {
229  /* since these are 'full' buckets we don't put them
230  * at the top but right after as the top is likely not
231  * full. */
232  tail->next = flow_spare_pool->next;
233  flow_spare_pool->next = head;
234  }
235 
236  flow_spare_pool_flow_cnt += flow_cnt;
237 #ifdef FSP_VALIDATE
238  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
239 #endif
240  SCMutexUnlock(&flow_spare_pool_m);
241  }
242  }
243 }
244 
246 {
247  SCMutexLock(&flow_spare_pool_m);
248  for (uint32_t cnt = 0; cnt < flow_config.prealloc; ) {
249  FlowSparePool *p = FlowSpareGetPool();
250  if (p == NULL) {
251  FatalError("failed to initialize flow pool");
252  }
253  FlowSparePoolUpdateBlock(p);
254  cnt += p->queue.len;
255 
256  /* prepend to list */
257  p->next = flow_spare_pool;
258  flow_spare_pool = p;
259  flow_spare_pool_flow_cnt = cnt;
260  }
261  SCMutexUnlock(&flow_spare_pool_m);
262 }
263 
265 {
266  SCMutexLock(&flow_spare_pool_m);
267  for (FlowSparePool *p = flow_spare_pool; p != NULL; ) {
268  uint32_t cnt = 0;
269  Flow *f;
270  while ((f = FlowQueuePrivateGetFromTop(&p->queue))) {
271  FlowFree(f);
272  cnt++;
273  }
274  flow_spare_pool_flow_cnt -= cnt;
275  FlowSparePool *next = p->next;
276  SCFree(p);
277  p = next;
278  }
279  flow_spare_pool = NULL;
280  SCMutexUnlock(&flow_spare_pool_m);
281 }
FlowSparePoolUpdate
void FlowSparePoolUpdate(uint32_t size)
Definition: flow-spare-pool.c:171
FlowSparePoolReturnFlow
void FlowSparePoolReturnFlow(Flow *f)
Definition: flow-spare-pool.c:100
FlowSpareGetPoolSize
uint32_t FlowSpareGetPoolSize(void)
Definition: flow-spare-pool.c:47
flow-util.h
FlowSpareGetFromPool
FlowQueuePrivate FlowSpareGetFromPool(void)
Definition: flow-spare-pool.c:127
FlowSparePool
Definition: flow-spare-pool.c:37
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
threads.h
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:357
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
SCMUTEX_INITIALIZER
#define SCMUTEX_INITIALIZER
Definition: threads-debug.h:121
FlowQueuePrivate_::len
uint32_t len
Definition: flow-queue.h:44
FlowSparePoolReturnFlows
void FlowSparePoolReturnFlows(FlowQueuePrivate *fqp)
Definition: flow-spare-pool.c:122
FlowCnf_::prealloc
uint32_t prealloc
Definition: flow.h:295
flow-spare-pool.h
util-debug.h
util-error.h
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
util-print.h
FlowQueuePrivateGetFromTop
Flow * FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc)
Definition: flow-queue.c:151
flow-queue.h
FlowSparePool::queue
FlowQueuePrivate queue
Definition: flow-spare-pool.c:38
tail
Host * tail
Definition: host.h:2
suricata-common.h
FlowFree
void FlowFree(Flow *f)
cleanup & free the memory of a flow
Definition: flow-util.c:83
flow_config
FlowConfig flow_config
Definition: flow.c:99
FlowSparePoolDestroy
void FlowSparePoolDestroy(void)
Definition: flow-spare-pool.c:264
FatalError
#define FatalError(...)
Definition: util-debug.h:502
util-validate.h
FlowQueuePrivate_
Definition: flow-queue.h:41
head
Flow * head
Definition: flow-hash.h:1
SCFree
#define SCFree(p)
Definition: util-mem.h:61
FlowSparePool::next
struct FlowSparePool * next
Definition: flow-spare-pool.c:39
FlowSparePoolInit
void FlowSparePoolInit(void)
Definition: flow-spare-pool.c:245
FlowQueuePrivateAppendFlow
void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f)
Definition: flow-queue.c:65
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:54
FlowSparePool
struct FlowSparePool FlowSparePool
SCCalloc
#define SCCalloc(nm, sz)
Definition: util-mem.h:53
SCMutex
#define SCMutex
Definition: threads-debug.h:114
DEBUG_VALIDATE_BUG_ON
#define DEBUG_VALIDATE_BUG_ON(exp)
Definition: util-validate.h:111