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 "debug.h"
29 #include "flow-private.h"
30 #include "flow-queue.h"
31 #include "flow-util.h"
32 #include "flow-spare-pool.h"
33 #include "util-error.h"
34 #include "util-debug.h"
35 #include "util-print.h"
36 #include "util-validate.h"
37 
38 typedef struct FlowSparePool {
42 
43 static uint32_t flow_spare_pool_flow_cnt = 0;
44 static uint32_t flow_spare_pool_block_size = 100;
45 static FlowSparePool *flow_spare_pool = NULL;
46 static SCMutex flow_spare_pool_m = SCMUTEX_INITIALIZER;
47 
48 uint32_t FlowSpareGetPoolSize(void)
49 {
50  uint32_t size;
51  SCMutexLock(&flow_spare_pool_m);
52  size = flow_spare_pool_flow_cnt;
53  SCMutexUnlock(&flow_spare_pool_m);
54  return size;
55 }
56 
57 static FlowSparePool *FlowSpareGetPool(void)
58 {
59  FlowSparePool *p = SCCalloc(1, sizeof(*p));
60  if (p == NULL)
61  return NULL;
62  return p;
63 }
64 
65 static bool FlowSparePoolUpdateBlock(FlowSparePool *p)
66 {
67  DEBUG_VALIDATE_BUG_ON(p == NULL);
68 
69  for (uint32_t i = p->queue.len; i < flow_spare_pool_block_size; i++)
70  {
71  Flow *f = FlowAlloc();
72  if (f == NULL)
73  return false;
75  }
76  return true;
77 }
78 
79 #ifdef FSP_VALIDATE
80 static void Validate(FlowSparePool *top, const uint32_t target)
81 {
82  if (top == NULL) {
83  assert(target == 0);
84  return;
85  }
86 
87  assert(top->queue.len >= 1);
88  //if (top->next != NULL)
89  // assert(top->next->queue.len == flow_spare_pool_block_size);
90 
91  uint32_t cnt = 0;
92  for (FlowSparePool *p = top; p != NULL; p = p->next)
93  {
94  assert(p->queue.len);
95  cnt += p->queue.len;
96  }
97  assert(cnt == target);
98 }
99 #endif
100 
102 {
103  SCMutexLock(&flow_spare_pool_m);
104  if (flow_spare_pool == NULL) {
105  flow_spare_pool = FlowSpareGetPool();
106  }
107  DEBUG_VALIDATE_BUG_ON(flow_spare_pool == NULL);
108 
109  /* if the top is full, get a new block */
110  if (flow_spare_pool->queue.len >= flow_spare_pool_block_size) {
111  FlowSparePool *p = FlowSpareGetPool();
112  DEBUG_VALIDATE_BUG_ON(p == NULL);
113  p->next = flow_spare_pool;
114  flow_spare_pool = p;
115  }
116  /* add to the (possibly new) top */
117  FlowQueuePrivateAppendFlow(&flow_spare_pool->queue, f);
118  flow_spare_pool_flow_cnt++;
119 
120  SCMutexUnlock(&flow_spare_pool_m);
121 }
122 
124 {
125 
126 }
127 
129 {
130  SCMutexLock(&flow_spare_pool_m);
131  if (flow_spare_pool == NULL || flow_spare_pool_flow_cnt == 0) {
132  SCMutexUnlock(&flow_spare_pool_m);
133  FlowQueuePrivate empty = { NULL, NULL, 0 };
134  return empty;
135  }
136 
137  /* top if full or its the only block we have */
138  if (flow_spare_pool->queue.len >= flow_spare_pool_block_size || flow_spare_pool->next == NULL) {
139  FlowSparePool *p = flow_spare_pool;
140  flow_spare_pool = p->next;
141  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
142  flow_spare_pool_flow_cnt -= p->queue.len;
143 #ifdef FSP_VALIDATE
144  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
145 #endif
146  SCMutexUnlock(&flow_spare_pool_m);
147 
148  FlowQueuePrivate ret = p->queue;
149  SCFree(p);
150  return ret;
151  /* next should always be full if it exists */
152  } else if (flow_spare_pool->next != NULL) {
153  FlowSparePool *p = flow_spare_pool->next;
154  flow_spare_pool->next = p->next;
155  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
156  flow_spare_pool_flow_cnt -= p->queue.len;
157 #ifdef FSP_VALIDATE
158  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
159 #endif
160  SCMutexUnlock(&flow_spare_pool_m);
161 
162  FlowQueuePrivate ret = p->queue;
163  SCFree(p);
164  return ret;
165  }
166 
167  SCMutexUnlock(&flow_spare_pool_m);
168  FlowQueuePrivate empty = { NULL, NULL, 0 };
169  return empty;
170 }
171 
172 void FlowSparePoolUpdate(uint32_t size)
173 {
174  const int64_t todo = (int64_t)flow_config.prealloc - (int64_t)size;
175  if (todo < 0) {
176  /* remove one block at most at a time */
177  uint32_t to_remove = (uint32_t)(todo * -1) / 10;
178  if (to_remove < flow_spare_pool_block_size)
179  return;
180 
181  FlowSparePool *p = NULL;
182  SCMutexLock(&flow_spare_pool_m);
183  p = flow_spare_pool;
184  if (p != NULL) {
185  flow_spare_pool = p->next;
186  flow_spare_pool_flow_cnt -= 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(SC_ERR_FLOW_INIT, "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:172
FlowSparePoolReturnFlow
void FlowSparePoolReturnFlow(Flow *f)
Definition: flow-spare-pool.c:101
FlowSpareGetPoolSize
uint32_t FlowSpareGetPoolSize(void)
Definition: flow-spare-pool.c:48
flow-util.h
FlowSpareGetFromPool
FlowQueuePrivate FlowSpareGetFromPool(void)
Definition: flow-spare-pool.c:128
FlowSparePool
Definition: flow-spare-pool.c:38
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
threads.h
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:347
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:123
FlowCnf_::prealloc
uint32_t prealloc
Definition: flow.h:287
flow-spare-pool.h
SC_ERR_FLOW_INIT
@ SC_ERR_FLOW_INIT
Definition: util-error.h:237
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:152
flow-queue.h
FlowSparePool::queue
FlowQueuePrivate queue
Definition: flow-spare-pool.c:39
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:80
flow_config
FlowConfig flow_config
Definition: flow.c:98
FlowSparePoolDestroy
void FlowSparePoolDestroy(void)
Definition: flow-spare-pool.c:264
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
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:40
FlowSparePoolInit
void FlowSparePoolInit(void)
Definition: flow-spare-pool.c:245
FlowQueuePrivateAppendFlow
void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f)
Definition: flow-queue.c:66
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:51
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
debug.h