suricata
flow-spare-pool.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2023 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;
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  FlowSparePool *p = FlowSpareGetPool();
125  DEBUG_VALIDATE_BUG_ON(p == NULL);
126  p->queue = *fqp;
127 
128  SCMutexLock(&flow_spare_pool_m);
129  flow_spare_pool_flow_cnt += fqp->len;
130  if (flow_spare_pool != NULL) {
132  /* full block insert */
133 
134  if (flow_spare_pool->queue.len < flow_spare_pool_block_size) {
135  p->next = flow_spare_pool->next;
136  flow_spare_pool->next = p;
137  p = NULL;
138  } else {
139  p->next = flow_spare_pool;
140  flow_spare_pool = p;
141  p = NULL;
142  }
143  } else {
144  /* incomplete block insert */
145 
146  if (p->queue.len + flow_spare_pool->queue.len <= flow_spare_pool_block_size) {
147  FlowQueuePrivateAppendPrivate(&flow_spare_pool->queue, &p->queue);
148  /* free 'p' outside of lock below */
149  } else {
150  // put smallest first
151  if (p->queue.len < flow_spare_pool->queue.len) {
152  p->next = flow_spare_pool;
153  flow_spare_pool = p;
154  } else {
155  p->next = flow_spare_pool->next;
156  flow_spare_pool->next = p;
157  }
158  p = NULL;
159  }
160  }
161  } else {
162  p->next = flow_spare_pool;
163  flow_spare_pool = p;
164  p = NULL;
165  }
166  SCMutexUnlock(&flow_spare_pool_m);
167 
168  FlowQueuePrivate empty = { NULL, NULL, 0 };
169  *fqp = empty;
170 
171  if (p != NULL)
172  SCFree(p);
173 }
174 
176 {
177  SCMutexLock(&flow_spare_pool_m);
178  if (flow_spare_pool == NULL || flow_spare_pool_flow_cnt == 0) {
179  SCMutexUnlock(&flow_spare_pool_m);
180  FlowQueuePrivate empty = { NULL, NULL, 0 };
181  return empty;
182  }
183 
184  /* top if full or its the only block we have */
185  if (flow_spare_pool->queue.len >= flow_spare_pool_block_size || flow_spare_pool->next == NULL) {
186  FlowSparePool *p = flow_spare_pool;
187  flow_spare_pool = p->next;
188  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
189  flow_spare_pool_flow_cnt -= p->queue.len;
190 #ifdef FSP_VALIDATE
191  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
192 #endif
193  SCMutexUnlock(&flow_spare_pool_m);
194 
195  FlowQueuePrivate ret = p->queue;
196  SCFree(p);
197  return ret;
198  /* next should always be full if it exists */
199  } else if (flow_spare_pool->next != NULL) {
200  FlowSparePool *p = flow_spare_pool->next;
201  flow_spare_pool->next = p->next;
202  DEBUG_VALIDATE_BUG_ON(flow_spare_pool_flow_cnt < p->queue.len);
203  flow_spare_pool_flow_cnt -= p->queue.len;
204 #ifdef FSP_VALIDATE
205  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
206 #endif
207  SCMutexUnlock(&flow_spare_pool_m);
208 
209  FlowQueuePrivate ret = p->queue;
210  SCFree(p);
211  return ret;
212  }
213 
214  SCMutexUnlock(&flow_spare_pool_m);
215  FlowQueuePrivate empty = { NULL, NULL, 0 };
216  return empty;
217 }
218 
219 void FlowSparePoolUpdate(uint32_t size)
220 {
221  const int64_t todo = (int64_t)flow_config.prealloc - (int64_t)size;
222  if (todo < 0) {
223  uint32_t to_remove = (uint32_t)(todo * -1) / 10;
224  while (to_remove) {
225  if (to_remove < flow_spare_pool_block_size)
226  return;
227 
228  FlowSparePool *p = NULL;
229  SCMutexLock(&flow_spare_pool_m);
230  p = flow_spare_pool;
231  if (p != NULL) {
232  flow_spare_pool = p->next;
233  flow_spare_pool_flow_cnt -= p->queue.len;
234  to_remove -= p->queue.len;
235  }
236  SCMutexUnlock(&flow_spare_pool_m);
237 
238  if (p != NULL) {
239  Flow *f;
240  while ((f = FlowQueuePrivateGetFromTop(&p->queue))) {
241  FlowFree(f);
242  }
243  SCFree(p);
244  }
245  }
246  } else if (todo > 0) {
247  FlowSparePool *head = NULL, *tail = NULL;
248 
249  uint32_t blocks = ((uint32_t)todo / flow_spare_pool_block_size) + 1;
250 
251  uint32_t flow_cnt = 0;
252  for (uint32_t cnt = 0; cnt < blocks; cnt++) {
253  FlowSparePool *p = FlowSpareGetPool();
254  if (p == NULL) {
255  break;
256  }
257  const bool ok = FlowSparePoolUpdateBlock(p);
258  if (p->queue.len == 0) {
259  SCFree(p);
260  break;
261  }
262  flow_cnt += p->queue.len;
263 
264  /* prepend to list */
265  p->next = head;
266  head = p;
267  if (tail == NULL)
268  tail = p;
269  if (!ok)
270  break;
271  }
272  if (head) {
273  SCMutexLock(&flow_spare_pool_m);
274  if (flow_spare_pool == NULL) {
275  flow_spare_pool = head;
276  } else if (tail != NULL) {
277  /* since these are 'full' buckets we don't put them
278  * at the top but right after as the top is likely not
279  * full. */
280  tail->next = flow_spare_pool->next;
281  flow_spare_pool->next = head;
282  }
283 
284  flow_spare_pool_flow_cnt += flow_cnt;
285 #ifdef FSP_VALIDATE
286  Validate(flow_spare_pool, flow_spare_pool_flow_cnt);
287 #endif
288  SCMutexUnlock(&flow_spare_pool_m);
289  }
290  }
291 }
292 
294 {
295  SCMutexLock(&flow_spare_pool_m);
296  for (uint32_t cnt = 0; cnt < flow_config.prealloc; ) {
297  FlowSparePool *p = FlowSpareGetPool();
298  if (p == NULL) {
299  FatalError("failed to initialize flow pool");
300  }
301  FlowSparePoolUpdateBlock(p);
302  cnt += p->queue.len;
303 
304  /* prepend to list */
305  p->next = flow_spare_pool;
306  flow_spare_pool = p;
307  flow_spare_pool_flow_cnt = cnt;
308  }
309  SCMutexUnlock(&flow_spare_pool_m);
310 }
311 
313 {
314  SCMutexLock(&flow_spare_pool_m);
315  for (FlowSparePool *p = flow_spare_pool; p != NULL; ) {
316  uint32_t cnt = 0;
317  Flow *f;
318  while ((f = FlowQueuePrivateGetFromTop(&p->queue))) {
319  FlowFree(f);
320  cnt++;
321  }
322  flow_spare_pool_flow_cnt -= cnt;
323  FlowSparePool *next = p->next;
324  SCFree(p);
325  p = next;
326  }
327  flow_spare_pool = NULL;
328  SCMutexUnlock(&flow_spare_pool_m);
329 }
FlowSparePoolUpdate
void FlowSparePoolUpdate(uint32_t size)
Definition: flow-spare-pool.c:219
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:175
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:351
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:290
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
FlowQueuePrivateAppendPrivate
void FlowQueuePrivateAppendPrivate(FlowQueuePrivate *dest, FlowQueuePrivate *src)
Definition: flow-queue.c:88
flow-queue.h
FlowSparePool::queue
FlowQueuePrivate queue
Definition: flow-spare-pool.c:38
cnt
uint32_t cnt
Definition: tmqh-packetpool.h:7
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:82
flow_config
FlowConfig flow_config
Definition: flow.c:102
FlowSparePoolDestroy
void FlowSparePoolDestroy(void)
Definition: flow-spare-pool.c:312
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:293
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:103
flow_spare_pool_block_size
uint32_t flow_spare_pool_block_size
Definition: flow-spare-pool.c:43