suricata
flow-hash.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2022 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  * \author Pablo Rincon Crespo <pablo.rincon.crespo@gmail.com>
23  *
24  * Flow Hashing functions.
25  */
26 
27 #include "suricata-common.h"
28 #include "threads.h"
29 
30 #include "decode.h"
31 #include "detect-engine-state.h"
32 
33 #include "flow.h"
34 #include "flow-hash.h"
35 #include "flow-util.h"
36 #include "flow-private.h"
37 #include "flow-manager.h"
38 #include "flow-storage.h"
39 #include "flow-timeout.h"
40 #include "flow-spare-pool.h"
41 #include "app-layer-parser.h"
42 
43 #include "util-time.h"
44 #include "util-debug.h"
45 
46 #include "util-hash-lookup3.h"
47 
48 #include "conf.h"
49 #include "output.h"
50 #include "output-flow.h"
51 #include "stream-tcp.h"
52 #include "util-exception-policy.h"
53 
55 
56 
57 FlowBucket *flow_hash;
58 SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx);
59 SC_ATOMIC_EXTERN(unsigned int, flow_flags);
60 
61 static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv, const SCTime_t ts);
62 
63 /** \brief compare two raw ipv6 addrs
64  *
65  * \note we don't care about the real ipv6 ip's, this is just
66  * to consistently fill the FlowHashKey6 struct, without all
67  * the SCNtohl calls.
68  *
69  * \warning do not use elsewhere unless you know what you're doing.
70  * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
71  * what you are looking for.
72  */
73 static inline int FlowHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
74 {
75  for (int i = 0; i < 4; i++) {
76  if (a[i] > b[i])
77  return 1;
78  if (a[i] < b[i])
79  break;
80  }
81 
82  return 0;
83 }
84 
85 typedef struct FlowHashKey4_ {
86  union {
87  struct {
88  uint32_t addrs[2];
89  uint16_t ports[2];
90  uint16_t proto; /**< u16 so proto and recur add up to u32 */
91  uint16_t recur; /**< u16 so proto and recur add up to u32 */
92  uint16_t vlan_id[2];
93  };
94  const uint32_t u32[5];
95  };
97 
98 typedef struct FlowHashKey6_ {
99  union {
100  struct {
101  uint32_t src[4], dst[4];
102  uint16_t ports[2];
103  uint16_t proto; /**< u16 so proto and recur add up to u32 */
104  uint16_t recur; /**< u16 so proto and recur add up to u32 */
105  uint16_t vlan_id[2];
106  };
107  const uint32_t u32[11];
108  };
110 
111 uint32_t FlowGetIpPairProtoHash(const Packet *p)
112 {
113  uint32_t hash = 0;
114  if (p->ip4h != NULL) {
115  FlowHashKey4 fhk;
116 
117  int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
118  fhk.addrs[1 - ai] = p->src.addr_data32[0];
119  fhk.addrs[ai] = p->dst.addr_data32[0];
120 
121  fhk.ports[0] = 0xfedc;
122  fhk.ports[1] = 0xba98;
123 
124  fhk.proto = (uint16_t)p->proto;
125  fhk.recur = (uint16_t)p->recursion_level;
126  /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
127  * is disabled. */
128  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
129  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
130 
131  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
132  } else if (p->ip6h != NULL) {
133  FlowHashKey6 fhk;
134  if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
135  fhk.src[0] = p->src.addr_data32[0];
136  fhk.src[1] = p->src.addr_data32[1];
137  fhk.src[2] = p->src.addr_data32[2];
138  fhk.src[3] = p->src.addr_data32[3];
139  fhk.dst[0] = p->dst.addr_data32[0];
140  fhk.dst[1] = p->dst.addr_data32[1];
141  fhk.dst[2] = p->dst.addr_data32[2];
142  fhk.dst[3] = p->dst.addr_data32[3];
143  } else {
144  fhk.src[0] = p->dst.addr_data32[0];
145  fhk.src[1] = p->dst.addr_data32[1];
146  fhk.src[2] = p->dst.addr_data32[2];
147  fhk.src[3] = p->dst.addr_data32[3];
148  fhk.dst[0] = p->src.addr_data32[0];
149  fhk.dst[1] = p->src.addr_data32[1];
150  fhk.dst[2] = p->src.addr_data32[2];
151  fhk.dst[3] = p->src.addr_data32[3];
152  }
153 
154  fhk.ports[0] = 0xfedc;
155  fhk.ports[1] = 0xba98;
156  fhk.proto = (uint16_t)p->proto;
157  fhk.recur = (uint16_t)p->recursion_level;
158  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
159  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
160 
161  hash = hashword(fhk.u32, 11, flow_config.hash_rand);
162  }
163  return hash;
164 }
165 
166 /* calculate the hash key for this packet
167  *
168  * we're using:
169  * hash_rand -- set at init time
170  * source port
171  * destination port
172  * source address
173  * destination address
174  * recursion level -- for tunnels, make sure different tunnel layers can
175  * never get mixed up.
176  *
177  * For ICMP we only consider UNREACHABLE errors atm.
178  */
179 static inline uint32_t FlowGetHash(const Packet *p)
180 {
181  uint32_t hash = 0;
182 
183  if (p->ip4h != NULL) {
184  if (p->tcph != NULL || p->udph != NULL) {
185  FlowHashKey4 fhk;
186 
187  int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
188  fhk.addrs[1-ai] = p->src.addr_data32[0];
189  fhk.addrs[ai] = p->dst.addr_data32[0];
190 
191  const int pi = (p->sp > p->dp);
192  fhk.ports[1-pi] = p->sp;
193  fhk.ports[pi] = p->dp;
194 
195  fhk.proto = (uint16_t)p->proto;
196  fhk.recur = (uint16_t)p->recursion_level;
197  /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
198  * is disabled. */
199  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
200  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
201 
202  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
203 
204  } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) {
205  uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p));
206  uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p));
207  FlowHashKey4 fhk;
208 
209  const int ai = (psrc > pdst);
210  fhk.addrs[1-ai] = psrc;
211  fhk.addrs[ai] = pdst;
212 
213  const int pi = (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport);
214  fhk.ports[1-pi] = p->icmpv4vars.emb_sport;
215  fhk.ports[pi] = p->icmpv4vars.emb_dport;
216 
217  fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p);
218  fhk.recur = (uint16_t)p->recursion_level;
219  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
220  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
221 
222  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
223 
224  } else {
225  FlowHashKey4 fhk;
226  const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
227  fhk.addrs[1-ai] = p->src.addr_data32[0];
228  fhk.addrs[ai] = p->dst.addr_data32[0];
229  fhk.ports[0] = 0xfeed;
230  fhk.ports[1] = 0xbeef;
231  fhk.proto = (uint16_t)p->proto;
232  fhk.recur = (uint16_t)p->recursion_level;
233  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
234  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
235 
236  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
237  }
238  } else if (p->ip6h != NULL) {
239  FlowHashKey6 fhk;
240  if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
241  fhk.src[0] = p->src.addr_data32[0];
242  fhk.src[1] = p->src.addr_data32[1];
243  fhk.src[2] = p->src.addr_data32[2];
244  fhk.src[3] = p->src.addr_data32[3];
245  fhk.dst[0] = p->dst.addr_data32[0];
246  fhk.dst[1] = p->dst.addr_data32[1];
247  fhk.dst[2] = p->dst.addr_data32[2];
248  fhk.dst[3] = p->dst.addr_data32[3];
249  } else {
250  fhk.src[0] = p->dst.addr_data32[0];
251  fhk.src[1] = p->dst.addr_data32[1];
252  fhk.src[2] = p->dst.addr_data32[2];
253  fhk.src[3] = p->dst.addr_data32[3];
254  fhk.dst[0] = p->src.addr_data32[0];
255  fhk.dst[1] = p->src.addr_data32[1];
256  fhk.dst[2] = p->src.addr_data32[2];
257  fhk.dst[3] = p->src.addr_data32[3];
258  }
259 
260  const int pi = (p->sp > p->dp);
261  fhk.ports[1-pi] = p->sp;
262  fhk.ports[pi] = p->dp;
263  fhk.proto = (uint16_t)p->proto;
264  fhk.recur = (uint16_t)p->recursion_level;
265  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
266  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
267 
268  hash = hashword(fhk.u32, 11, flow_config.hash_rand);
269  }
270 
271  return hash;
272 }
273 
274 /**
275  * Basic hashing function for FlowKey
276  *
277  * \note Function only used for bypass and TCP or UDP flows
278  *
279  * \note this is only used at start to create Flow from pinned maps
280  * so fairness is not an issue
281  */
282 uint32_t FlowKeyGetHash(FlowKey *fk)
283 {
284  uint32_t hash = 0;
285 
286  if (fk->src.family == AF_INET) {
287  FlowHashKey4 fhk;
288  int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]);
289  fhk.addrs[1-ai] = fk->src.address.address_un_data32[0];
290  fhk.addrs[ai] = fk->dst.address.address_un_data32[0];
291 
292  const int pi = (fk->sp > fk->dp);
293  fhk.ports[1-pi] = fk->sp;
294  fhk.ports[pi] = fk->dp;
295 
296  fhk.proto = (uint16_t)fk->proto;
297  fhk.recur = (uint16_t)fk->recursion_level;
298  fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
299  fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
300 
301  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
302  } else {
303  FlowHashKey6 fhk;
304  if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32,
306  fhk.src[0] = fk->src.address.address_un_data32[0];
307  fhk.src[1] = fk->src.address.address_un_data32[1];
308  fhk.src[2] = fk->src.address.address_un_data32[2];
309  fhk.src[3] = fk->src.address.address_un_data32[3];
310  fhk.dst[0] = fk->dst.address.address_un_data32[0];
311  fhk.dst[1] = fk->dst.address.address_un_data32[1];
312  fhk.dst[2] = fk->dst.address.address_un_data32[2];
313  fhk.dst[3] = fk->dst.address.address_un_data32[3];
314  } else {
315  fhk.src[0] = fk->dst.address.address_un_data32[0];
316  fhk.src[1] = fk->dst.address.address_un_data32[1];
317  fhk.src[2] = fk->dst.address.address_un_data32[2];
318  fhk.src[3] = fk->dst.address.address_un_data32[3];
319  fhk.dst[0] = fk->src.address.address_un_data32[0];
320  fhk.dst[1] = fk->src.address.address_un_data32[1];
321  fhk.dst[2] = fk->src.address.address_un_data32[2];
322  fhk.dst[3] = fk->src.address.address_un_data32[3];
323  }
324 
325  const int pi = (fk->sp > fk->dp);
326  fhk.ports[1-pi] = fk->sp;
327  fhk.ports[pi] = fk->dp;
328  fhk.proto = (uint16_t)fk->proto;
329  fhk.recur = (uint16_t)fk->recursion_level;
330  fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
331  fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
332 
333  hash = hashword(fhk.u32, 11, flow_config.hash_rand);
334  }
335  return hash;
336 }
337 
338 static inline bool CmpAddrs(const uint32_t addr1[4], const uint32_t addr2[4])
339 {
340  return addr1[0] == addr2[0] && addr1[1] == addr2[1] &&
341  addr1[2] == addr2[2] && addr1[3] == addr2[3];
342 }
343 
344 static inline bool CmpAddrsAndPorts(const uint32_t src1[4],
345  const uint32_t dst1[4], Port src_port1, Port dst_port1,
346  const uint32_t src2[4], const uint32_t dst2[4], Port src_port2,
347  Port dst_port2)
348 {
349  /* Compare the source and destination addresses. If they are not equal,
350  * compare the first source address with the second destination address,
351  * and vice versa. Likewise for ports. */
352  return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
353  src_port1 == src_port2 && dst_port1 == dst_port2) ||
354  (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
355  src_port1 == dst_port2 && dst_port1 == src_port2);
356 }
357 
358 static inline bool CmpVlanIds(const uint16_t vlan_id1[2], const uint16_t vlan_id2[2])
359 {
360  return ((vlan_id1[0] ^ vlan_id2[0]) & g_vlan_mask) == 0 &&
361  ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0;
362 }
363 
364 /* Since two or more flows can have the same hash key, we need to compare
365  * the flow with the current packet or flow key. */
366 static inline bool CmpFlowPacket(const Flow *f, const Packet *p)
367 {
368  const uint32_t *f_src = f->src.address.address_un_data32;
369  const uint32_t *f_dst = f->dst.address.address_un_data32;
370  const uint32_t *p_src = p->src.address.address_un_data32;
371  const uint32_t *p_dst = p->dst.address.address_un_data32;
372  return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp,
373  p->dp) && f->proto == p->proto &&
374  f->recursion_level == p->recursion_level &&
375  CmpVlanIds(f->vlan_id, p->vlan_id);
376 }
377 
378 static inline bool CmpFlowKey(const Flow *f, const FlowKey *k)
379 {
380  const uint32_t *f_src = f->src.address.address_un_data32;
381  const uint32_t *f_dst = f->dst.address.address_un_data32;
382  const uint32_t *k_src = k->src.address.address_un_data32;
383  const uint32_t *k_dst = k->dst.address.address_un_data32;
384  return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp,
385  k->dp) && f->proto == k->proto &&
386  f->recursion_level == k->recursion_level &&
387  CmpVlanIds(f->vlan_id, k->vlan_id);
388 }
389 
390 static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4],
391  const uint32_t dst1[4], uint8_t icmp_s_type1, uint8_t icmp_d_type1,
392  const uint32_t src2[4], const uint32_t dst2[4], uint8_t icmp_s_type2,
393  uint8_t icmp_d_type2)
394 {
395  /* Compare the source and destination addresses. If they are not equal,
396  * compare the first source address with the second destination address,
397  * and vice versa. Likewise for icmp types. */
398  return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
399  icmp_s_type1 == icmp_s_type2 && icmp_d_type1 == icmp_d_type2) ||
400  (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
401  icmp_s_type1 == icmp_d_type2 && icmp_d_type1 == icmp_s_type2);
402 }
403 
404 static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p)
405 {
406  const uint32_t *f_src = f->src.address.address_un_data32;
407  const uint32_t *f_dst = f->dst.address.address_un_data32;
408  const uint32_t *p_src = p->src.address.address_un_data32;
409  const uint32_t *p_dst = p->dst.address.address_un_data32;
410  return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type,
411  f->icmp_d.type, p_src, p_dst, p->icmp_s.type, p->icmp_d.type) &&
412  f->proto == p->proto && f->recursion_level == p->recursion_level &&
413  CmpVlanIds(f->vlan_id, p->vlan_id);
414 }
415 
416 /**
417  * \brief See if a ICMP packet belongs to a flow by comparing the embedded
418  * packet in the ICMP error packet to the flow.
419  *
420  * \param f flow
421  * \param p ICMP packet
422  *
423  * \retval 1 match
424  * \retval 0 no match
425  */
426 static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
427 {
429  /* first check the direction of the flow, in other words, the client ->
430  * server direction as it's most likely the ICMP error will be a
431  * response to the clients traffic */
432  if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p))) &&
433  (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) &&
434  f->sp == p->icmpv4vars.emb_sport && f->dp == p->icmpv4vars.emb_dport &&
436  CmpVlanIds(f->vlan_id, p->vlan_id)) {
437  return 1;
438 
439  /* check the less likely case where the ICMP error was a response to
440  * a packet from the server. */
441  } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p))) &&
442  (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p))) &&
443  f->dp == p->icmpv4vars.emb_sport && f->sp == p->icmpv4vars.emb_dport &&
444  f->proto == ICMPV4_GET_EMB_PROTO(p) &&
445  f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id)) {
446  return 1;
447  }
448 
449  /* no match, fall through */
450  } else {
451  /* just treat ICMP as a normal proto for now */
452  return CmpFlowICMPPacket(f, p);
453  }
454 
455  return 0;
456 }
457 
458 /**
459  * \brief See if a IP-ESP packet belongs to a flow by comparing the SPI
460  *
461  * \param f flow
462  * \param p ESP packet
463  *
464  * \retval 1 match
465  * \retval 0 no match
466  */
467 static inline int FlowCompareESP(Flow *f, const Packet *p)
468 {
469  const uint32_t *f_src = f->src.address.address_un_data32;
470  const uint32_t *f_dst = f->dst.address.address_un_data32;
471  const uint32_t *p_src = p->src.address.address_un_data32;
472  const uint32_t *p_dst = p->dst.address.address_un_data32;
473 
474  return CmpAddrs(f_src, p_src) && CmpAddrs(f_dst, p_dst) && f->proto == p->proto &&
475  f->recursion_level == p->recursion_level && CmpVlanIds(f->vlan_id, p->vlan_id) &&
476  f->esp.spi == ESP_GET_SPI(p);
477 }
478 
480 {
481  p->flags |= PKT_WANTS_FLOW;
482  p->flow_hash = FlowGetHash(p);
483 }
484 
485 static inline int FlowCompare(Flow *f, const Packet *p)
486 {
487  if (p->proto == IPPROTO_ICMP) {
488  return FlowCompareICMPv4(f, p);
489  } else if (p->proto == IPPROTO_ESP) {
490  return FlowCompareESP(f, p);
491  } else {
492  return CmpFlowPacket(f, p);
493  }
494 }
495 
496 /**
497  * \brief Check if we should create a flow based on a packet
498  *
499  * We use this check to filter out flow creation based on:
500  * - ICMP error messages
501  * - TCP flags (emergency mode only)
502  *
503  * \param p packet
504  * \retval 1 true
505  * \retval 0 false
506  */
507 static inline int FlowCreateCheck(const Packet *p, const bool emerg)
508 {
509  /* if we're in emergency mode, don't try to create a flow for a TCP
510  * that is not a TCP SYN packet. */
511  if (emerg) {
512  if (PKT_IS_TCP(p)) {
513  if (p->tcph->th_flags == TH_SYN || !stream_config.midstream) {
514  ;
515  } else {
516  return 0;
517  }
518  }
519  }
520 
521  if (PKT_IS_ICMPV4(p)) {
522  if (ICMPV4_IS_ERROR_MSG(p)) {
523  return 0;
524  }
525  }
526 
527  return 1;
528 }
529 
530 static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv,
531  uint8_t proto)
532 {
533 #ifdef UNITTESTS
534  if (tv && dtv) {
535 #endif
538  switch (proto){
539  case IPPROTO_UDP:
541  break;
542  case IPPROTO_TCP:
544  break;
545  case IPPROTO_ICMP:
547  break;
548  case IPPROTO_ICMPV6:
550  break;
551  }
552 #ifdef UNITTESTS
553  }
554 #endif
555 }
556 
557 /** \internal
558  * \brief try to fetch a new set of flows from the master flow pool.
559  *
560  * If in emergency mode, do this only once a second at max to avoid trying
561  * to synchronise per packet in the worse case. */
562 static inline Flow *FlowSpareSync(ThreadVars *tv, FlowLookupStruct *fls,
563  const Packet *p, const bool emerg)
564 {
565  Flow *f = NULL;
566  bool spare_sync = false;
567  if (emerg) {
568  if ((uint32_t)SCTIME_SECS(p->ts) > fls->emerg_spare_sync_stamp) {
569  fls->spare_queue = FlowSpareGetFromPool(); /* local empty, (re)populate and try again */
570  spare_sync = true;
572  if (f == NULL) {
573  /* wait till next full sec before retrying */
574  fls->emerg_spare_sync_stamp = (uint32_t)SCTIME_SECS(p->ts);
575  }
576  }
577  } else {
578  fls->spare_queue = FlowSpareGetFromPool(); /* local empty, (re)populate and try again */
580  spare_sync = true;
581  }
582 #ifdef UNITTESTS
583  if (tv && fls->dtv) {
584 #endif
585  if (spare_sync) {
586  if (f != NULL) {
588  if (fls->spare_queue.len < 99) {
590  }
591  } else if (fls->spare_queue.len == 0) {
593  }
595  }
596 #ifdef UNITTESTS
597  }
598 #endif
599  return f;
600 }
601 
602 static inline void NoFlowHandleIPS(Packet *p)
603 {
605 }
606 
607 /**
608  * \brief Get a new flow
609  *
610  * Get a new flow. We're checking memcap first and will try to make room
611  * if the memcap is reached.
612  *
613  * \param tv thread vars
614  * \param fls lookup support vars
615  *
616  * \retval f *LOCKED* flow on succes, NULL on error.
617  */
618 static Flow *FlowGetNew(ThreadVars *tv, FlowLookupStruct *fls, Packet *p)
619 {
620  const bool emerg = ((SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0);
621 #ifdef DEBUG
622  if (g_eps_flow_memcap != UINT64_MAX && g_eps_flow_memcap == p->pcap_cnt) {
623  return NULL;
624  }
625 #endif
626  if (FlowCreateCheck(p, emerg) == 0) {
627  return NULL;
628  }
629 
630  /* get a flow from the spare queue */
632  if (f == NULL) {
633  f = FlowSpareSync(tv, fls, p, emerg);
634  }
635  if (f == NULL) {
636  /* If we reached the max memcap, we get a used flow */
637  if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) {
638  /* declare state of emergency */
639  if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) {
640  SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY);
643  }
644 
645  f = FlowGetUsedFlow(tv, fls->dtv, p->ts);
646  if (f == NULL) {
647  NoFlowHandleIPS(p);
648  return NULL;
649  }
650 #ifdef UNITTESTS
651  if (tv != NULL && fls->dtv != NULL) {
652 #endif
654 #ifdef UNITTESTS
655  }
656 #endif
657  /* flow is still locked from FlowGetUsedFlow() */
658  FlowUpdateCounter(tv, fls->dtv, p->proto);
659  return f;
660  }
661 
662  /* now see if we can alloc a new flow */
663  f = FlowAlloc();
664  if (f == NULL) {
665 #ifdef UNITTESTS
666  if (tv != NULL && fls->dtv != NULL) {
667 #endif
669 #ifdef UNITTESTS
670  }
671 #endif
672  NoFlowHandleIPS(p);
673  return NULL;
674  }
675 
676  /* flow is initialized but *unlocked* */
677  } else {
678  /* flow has been recycled before it went into the spare queue */
679 
680  /* flow is initialized (recylced) but *unlocked* */
681  }
682 
683  FLOWLOCK_WRLOCK(f);
684  FlowUpdateCounter(tv, fls->dtv, p->proto);
685  return f;
686 }
687 
688 static Flow *TcpReuseReplace(ThreadVars *tv, FlowLookupStruct *fls, FlowBucket *fb, Flow *old_f,
689  const uint32_t hash, Packet *p)
690 {
691 #ifdef UNITTESTS
692  if (tv != NULL && fls->dtv != NULL) {
693 #endif
695 #ifdef UNITTESTS
696  }
697 #endif
698  /* time out immediately */
699  old_f->timeout_at = 0;
700  /* get some settings that we move over to the new flow */
701  FlowThreadId thread_id[2] = { old_f->thread_id[0], old_f->thread_id[1] };
702 
703  /* flow is unlocked by caller */
704 
705  /* Get a new flow. It will be either a locked flow or NULL */
706  Flow *f = FlowGetNew(tv, fls, p);
707  if (f == NULL) {
708  return NULL;
709  }
710 
711  /* put at the start of the list */
712  f->next = fb->head;
713  fb->head = f;
714 
715  /* initialize and return */
716  FlowInit(f, p);
717  f->flow_hash = hash;
718  f->fb = fb;
720 
721  f->thread_id[0] = thread_id[0];
722  f->thread_id[1] = thread_id[1];
723 
725  return f;
726 }
727 
728 static inline bool FlowBelongsToUs(const ThreadVars *tv, const Flow *f)
729 {
730 #ifdef UNITTESTS
731  if (RunmodeIsUnittests()) {
732  return true;
733  }
734 #endif
735  return f->thread_id[0] == tv->id;
736 }
737 
738 static inline void MoveToWorkQueue(ThreadVars *tv, FlowLookupStruct *fls,
739  FlowBucket *fb, Flow *f, Flow *prev_f)
740 {
742 
743  /* remove from hash... */
744  if (prev_f) {
745  prev_f->next = f->next;
746  }
747  if (f == fb->head) {
748  fb->head = f->next;
749  }
750 
751  if (f->proto != IPPROTO_TCP || FlowBelongsToUs(tv, f)) { // TODO thread_id[] direction
752  f->fb = NULL;
753  f->next = NULL;
755  } else {
756  /* implied: TCP but our thread does not own it. So set it
757  * aside for the Flow Manager to pick it up. */
758  f->next = fb->evicted;
759  fb->evicted = f;
760  if (SC_ATOMIC_GET(f->fb->next_ts) != 0) {
761  SC_ATOMIC_SET(f->fb->next_ts, 0);
762  }
763  }
764 }
765 
766 static inline bool FlowIsTimedOut(const Flow *f, const uint32_t sec, const bool emerg)
767 {
768  if (unlikely(f->timeout_at < sec)) {
769  return true;
770  } else if (unlikely(emerg)) {
772 
773  int64_t timeout_at = f->timeout_at -
774  FlowGetFlowTimeoutDirect(flow_timeouts_delta, f->flow_state, f->protomap);
775  if ((int64_t)sec >= timeout_at)
776  return true;
777  }
778  return false;
779 }
780 
781 /** \brief Get Flow for packet
782  *
783  * Hash retrieval function for flows. Looks up the hash bucket containing the
784  * flow pointer. Then compares the packet with the found flow to see if it is
785  * the flow we need. If it isn't, walk the list until the right flow is found.
786  *
787  * If the flow is not found or the bucket was emtpy, a new flow is taken from
788  * the spare pool. The pool will alloc new flows as long as we stay within our
789  * memcap limit.
790  *
791  * The p->flow pointer is updated to point to the flow.
792  *
793  * \param tv thread vars
794  * \param dtv decode thread vars (for flow log api thread data)
795  *
796  * \retval f *LOCKED* flow or NULL
797  */
799 {
800  Flow *f = NULL;
801 
802  /* get our hash bucket and lock it */
803  const uint32_t hash = p->flow_hash;
804  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
805  FBLOCK_LOCK(fb);
806 
807  SCLogDebug("fb %p fb->head %p", fb, fb->head);
808 
809  /* see if the bucket already has a flow */
810  if (fb->head == NULL) {
811  f = FlowGetNew(tv, fls, p);
812  if (f == NULL) {
813  FBLOCK_UNLOCK(fb);
814  return NULL;
815  }
816 
817  /* flow is locked */
818  fb->head = f;
819 
820  /* got one, now lock, initialize and return */
821  FlowInit(f, p);
822  f->flow_hash = hash;
823  f->fb = fb;
825 
826  FlowReference(dest, f);
827 
828  FBLOCK_UNLOCK(fb);
829  return f;
830  }
831 
832  const bool emerg = (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY) != 0;
833  const uint32_t fb_nextts = !emerg ? SC_ATOMIC_GET(fb->next_ts) : 0;
834  /* ok, we have a flow in the bucket. Let's find out if it is our flow */
835  Flow *prev_f = NULL; /* previous flow */
836  f = fb->head;
837  do {
838  Flow *next_f = NULL;
839  const bool timedout = (fb_nextts < (uint32_t)SCTIME_SECS(p->ts) &&
840  FlowIsTimedOut(f, (uint32_t)SCTIME_SECS(p->ts), emerg));
841  if (timedout) {
842  FLOWLOCK_WRLOCK(f);
843  next_f = f->next;
844  MoveToWorkQueue(tv, fls, fb, f, prev_f);
845  FLOWLOCK_UNLOCK(f);
846  goto flow_removed;
847  } else if (FlowCompare(f, p) != 0) {
848  FLOWLOCK_WRLOCK(f);
849  /* found a matching flow that is not timed out */
850  if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) {
851  Flow *new_f = TcpReuseReplace(tv, fls, fb, f, hash, p);
852  if (prev_f == NULL) /* if we have no prev it means new_f is now our prev */
853  prev_f = new_f;
854  MoveToWorkQueue(tv, fls, fb, f, prev_f); /* evict old flow */
855  FLOWLOCK_UNLOCK(f); /* unlock old replaced flow */
856 
857  if (new_f == NULL) {
858  FBLOCK_UNLOCK(fb);
859  return NULL;
860  }
861  f = new_f;
862  }
863  FlowReference(dest, f);
864  FBLOCK_UNLOCK(fb);
865  return f; /* return w/o releasing flow lock */
866  }
867  /* unless we removed 'f', prev_f needs to point to
868  * current 'f' when adding a new flow below. */
869  prev_f = f;
870  next_f = f->next;
871 
872 flow_removed:
873  if (next_f == NULL) {
874  f = FlowGetNew(tv, fls, p);
875  if (f == NULL) {
876  FBLOCK_UNLOCK(fb);
877  return NULL;
878  }
879 
880  /* flow is locked */
881 
882  f->next = fb->head;
883  fb->head = f;
884 
885  /* initialize and return */
886  FlowInit(f, p);
887  f->flow_hash = hash;
888  f->fb = fb;
890  FlowReference(dest, f);
891  FBLOCK_UNLOCK(fb);
892  return f;
893  }
894  f = next_f;
895  } while (f != NULL);
896 
897  /* should be unreachable */
898  BUG_ON(1);
899  return NULL;
900 }
901 
902 static inline int FlowCompareKey(Flow *f, FlowKey *key)
903 {
904  if ((f->proto != IPPROTO_TCP) && (f->proto != IPPROTO_UDP))
905  return 0;
906  return CmpFlowKey(f, key);
907 }
908 
909 /** \brief Look for existing Flow using a flow id value
910  *
911  * Hash retrieval function for flows. Looks up the hash bucket containing the
912  * flow pointer. Then compares the packet with the found flow to see if it is
913  * the flow we need. If it isn't, walk the list until the right flow is found.
914  *
915  *
916  * \param flow_id Flow ID of the flow to look for
917  * \retval f *LOCKED* flow or NULL
918  */
919 
921 {
922  uint32_t hash = flow_id & 0x0000FFFF;
923  /* get our hash bucket and lock it */
924  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
925  FBLOCK_LOCK(fb);
926 
927  SCLogDebug("fb %p fb->head %p", fb, fb->head);
928 
929  /* return if the bucket don't have a flow */
930  if (fb->head == NULL) {
931  FBLOCK_UNLOCK(fb);
932  return NULL;
933  }
934 
935  /* ok, we have a flow in the bucket. Let's find out if it is our flow */
936  Flow *f = fb->head;
937 
938  /* see if this is the flow we are looking for */
939  if (FlowGetId(f) != flow_id) {
940  while (f) {
941  f = f->next;
942 
943  if (f == NULL) {
944  FBLOCK_UNLOCK(fb);
945  return NULL;
946  }
947  if (FlowGetId(f) != flow_id) {
948  /* found our flow, lock & return */
949  FLOWLOCK_WRLOCK(f);
950 
951  FBLOCK_UNLOCK(fb);
952  return f;
953  }
954  }
955  }
956 
957  /* lock & return */
958  FLOWLOCK_WRLOCK(f);
959 
960  FBLOCK_UNLOCK(fb);
961  return f;
962 }
963 
964 /** \brief Get or create a Flow using a FlowKey
965  *
966  * Hash retrieval function for flows. Looks up the hash bucket containing the
967  * flow pointer. Then compares the packet with the found flow to see if it is
968  * the flow we need. If it isn't, walk the list until the right flow is found.
969  * Return a new Flow if ever no Flow was found.
970  *
971  *
972  * \param key Pointer to FlowKey build using flow to look for
973  * \param ttime time to use for flow creation
974  * \param hash Value of the flow hash
975  * \retval f *LOCKED* flow or NULL
976  */
977 
978 Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
979 {
980  Flow *f = FlowGetExistingFlowFromHash(key, hash);
981 
982  if (f != NULL) {
983  return f;
984  }
985  /* TODO use spare pool */
986  /* now see if we can alloc a new flow */
987  f = FlowAlloc();
988  if (f == NULL) {
989  SCLogDebug("Can't get a spare flow at start");
990  return NULL;
991  }
992  f->proto = key->proto;
993  f->vlan_id[0] = key->vlan_id[0];
994  f->vlan_id[1] = key->vlan_id[1];
995  f->src.addr_data32[0] = key->src.addr_data32[0];
996  f->src.addr_data32[1] = key->src.addr_data32[1];
997  f->src.addr_data32[2] = key->src.addr_data32[2];
998  f->src.addr_data32[3] = key->src.addr_data32[3];
999  f->dst.addr_data32[0] = key->dst.addr_data32[0];
1000  f->dst.addr_data32[1] = key->dst.addr_data32[1];
1001  f->dst.addr_data32[2] = key->dst.addr_data32[2];
1002  f->dst.addr_data32[3] = key->dst.addr_data32[3];
1003  f->sp = key->sp;
1004  f->dp = key->dp;
1005  f->recursion_level = 0;
1006  f->flow_hash = hash;
1007  if (key->src.family == AF_INET) {
1008  f->flags |= FLOW_IPV4;
1009  } else if (key->src.family == AF_INET6) {
1010  f->flags |= FLOW_IPV6;
1011  }
1012 
1014  /* set timestamp to now */
1015  f->startts = SCTIME_FROM_TIMESPEC(ttime);
1016  f->lastts = f->startts;
1017 
1018  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
1019  FBLOCK_LOCK(fb);
1020  f->fb = fb;
1021  f->next = fb->head;
1022  fb->head = f;
1023  FLOWLOCK_WRLOCK(f);
1024  FBLOCK_UNLOCK(fb);
1025  return f;
1026 }
1027 
1028 /** \brief Look for existing Flow using a FlowKey
1029  *
1030  * Hash retrieval function for flows. Looks up the hash bucket containing the
1031  * flow pointer. Then compares the packet with the found flow to see if it is
1032  * the flow we need. If it isn't, walk the list until the right flow is found.
1033  *
1034  *
1035  * \param key Pointer to FlowKey build using flow to look for
1036  * \param hash Value of the flow hash
1037  * \retval f *LOCKED* flow or NULL
1038  */
1039 Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash)
1040 {
1041  /* get our hash bucket and lock it */
1042  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
1043  FBLOCK_LOCK(fb);
1044 
1045  SCLogDebug("fb %p fb->head %p", fb, fb->head);
1046 
1047  /* return if the bucket don't have a flow */
1048  if (fb->head == NULL) {
1049  FBLOCK_UNLOCK(fb);
1050  return NULL;
1051  }
1052 
1053  /* ok, we have a flow in the bucket. Let's find out if it is our flow */
1054  Flow *f = fb->head;
1055 
1056  /* see if this is the flow we are looking for */
1057  if (FlowCompareKey(f, key) == 0) {
1058  while (f) {
1059  f = f->next;
1060 
1061  if (f == NULL) {
1062  FBLOCK_UNLOCK(fb);
1063  return NULL;
1064  }
1065 
1066  if (FlowCompareKey(f, key) != 0) {
1067  /* found our flow, lock & return */
1068  FLOWLOCK_WRLOCK(f);
1069 
1070  FBLOCK_UNLOCK(fb);
1071  return f;
1072  }
1073  }
1074  }
1075 
1076  /* lock & return */
1077  FLOWLOCK_WRLOCK(f);
1078 
1079  FBLOCK_UNLOCK(fb);
1080  return f;
1081 }
1082 
1083 #define FLOW_GET_NEW_TRIES 5
1085 /* inline locking wrappers to make profiling easier */
1086 
1087 static inline int GetUsedTryLockBucket(FlowBucket *fb)
1088 {
1089  int r = FBLOCK_TRYLOCK(fb);
1090  return r;
1091 }
1092 static inline int GetUsedTryLockFlow(Flow *f)
1093 {
1094  int r = FLOWLOCK_TRYWRLOCK(f);
1095  return r;
1096 }
1097 static inline uint32_t GetUsedAtomicUpdate(const uint32_t val)
1098 {
1099  uint32_t r = SC_ATOMIC_ADD(flow_prune_idx, val);
1100  return r;
1101 }
1102 
1103 /** \internal
1104  * \brief check if flow has just seen an update.
1105  */
1106 static inline bool StillAlive(const Flow *f, const SCTime_t ts)
1107 {
1108  switch (f->flow_state) {
1109  case FLOW_STATE_NEW:
1110  if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 1) {
1111  return true;
1112  }
1113  break;
1115  if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 5) {
1116  return true;
1117  }
1118  break;
1119  case FLOW_STATE_CLOSED:
1120  if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) <= 3) {
1121  return true;
1122  }
1123  break;
1124  default:
1125  if (SCTIME_SECS(ts) - SCTIME_SECS(f->lastts) < 30) {
1126  return true;
1127  }
1128  break;
1129  }
1130  return false;
1131 }
1132 
1133 #ifdef UNITTESTS
1134  #define STATSADDUI64(cnt, value) \
1135  if (tv && dtv) { \
1136  StatsAddUI64(tv, dtv->cnt, (value)); \
1137  }
1138 #else
1139  #define STATSADDUI64(cnt, value) \
1140  StatsAddUI64(tv, dtv->cnt, (value));
1141 #endif
1142 
1143 /** \internal
1144  * \brief Get a flow from the hash directly.
1145  *
1146  * Called in conditions where the spare queue is empty and memcap is reached.
1147  *
1148  * Walks the hash until a flow can be freed. Timeouts are disregarded.
1149  * "flow_prune_idx" atomic int makes sure we don't start at the
1150  * top each time since that would clear the top of the hash leading to longer
1151  * and longer search times under high pressure (observed).
1152  *
1153  * \param tv thread vars
1154  * \param dtv decode thread vars (for flow log api thread data)
1155  *
1156  * \retval f flow or NULL
1157  */
1158 static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv, const SCTime_t ts)
1159 {
1160  uint32_t idx = GetUsedAtomicUpdate(FLOW_GET_NEW_TRIES) % flow_config.hash_size;
1161  uint32_t tried = 0;
1162 
1163  while (1) {
1164  if (tried++ > FLOW_GET_NEW_TRIES) {
1165  STATSADDUI64(counter_flow_get_used_eval, tried);
1166  break;
1167  }
1168  if (++idx >= flow_config.hash_size)
1169  idx = 0;
1170 
1171  FlowBucket *fb = &flow_hash[idx];
1172 
1173  if (SC_ATOMIC_GET(fb->next_ts) == UINT_MAX)
1174  continue;
1175 
1176  if (GetUsedTryLockBucket(fb) != 0) {
1177  STATSADDUI64(counter_flow_get_used_eval_busy, 1);
1178  continue;
1179  }
1180 
1181  Flow *f = fb->head;
1182  if (f == NULL) {
1183  FBLOCK_UNLOCK(fb);
1184  continue;
1185  }
1186 
1187  if (GetUsedTryLockFlow(f) != 0) {
1188  STATSADDUI64(counter_flow_get_used_eval_busy, 1);
1189  FBLOCK_UNLOCK(fb);
1190  continue;
1191  }
1192 
1193  if (StillAlive(f, ts)) {
1194  STATSADDUI64(counter_flow_get_used_eval_reject, 1);
1195  FBLOCK_UNLOCK(fb);
1196  FLOWLOCK_UNLOCK(f);
1197  continue;
1198  }
1199 
1200  /* remove from the hash */
1201  fb->head = f->next;
1202  f->next = NULL;
1203  f->fb = NULL;
1204  FBLOCK_UNLOCK(fb);
1205 
1206  /* rest of the flags is updated on-demand in output */
1208  if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
1210 
1211  /* invoke flow log api */
1212 #ifdef UNITTESTS
1213  if (dtv) {
1214 #endif
1217  }
1218 #ifdef UNITTESTS
1219  }
1220 #endif
1221 
1222  FlowClearMemory(f, f->protomap);
1223 
1224  /* leave locked */
1225 
1226  STATSADDUI64(counter_flow_get_used_eval, tried);
1227  return f;
1228  }
1229 
1230  STATSADDUI64(counter_flow_get_used_failed, 1);
1231  return NULL;
1232 }
FlowHashKey4_::ports
uint16_t ports[2]
Definition: flow-hash.c:89
FlowLookupStruct_::work_queue
FlowQueuePrivate work_queue
Definition: flow.h:547
FlowHashKey6_::recur
uint16_t recur
Definition: flow-hash.c:104
OutputFlowLog
TmEcode OutputFlowLog(ThreadVars *tv, void *thread_data, Flow *f)
Run flow logger(s)
Definition: output-flow.c:86
Packet_::proto
uint8_t proto
Definition: decode.h:450
FlowAddress_::address
union FlowAddress_::@115 address
DecodeThreadVars_::counter_flow_udp
uint16_t counter_flow_udp
Definition: decode.h:725
ts
uint64_t ts
Definition: source-erf-file.c:55
ExceptionPolicyApply
void ExceptionPolicyApply(Packet *p, enum ExceptionPolicy policy, enum PacketDropReason drop_reason)
Definition: util-exception-policy.c:66
DecodeThreadVars_::counter_flow_active
uint16_t counter_flow_active
Definition: decode.h:723
ICMPV4_GET_EMB_PROTO
#define ICMPV4_GET_EMB_PROTO(p)
Definition: decode-icmpv4.h:250
Flow_::recursion_level
uint8_t recursion_level
Definition: flow.h:380
StatsIncr
void StatsIncr(ThreadVars *tv, uint16_t id)
Increments the local counter.
Definition: counters.c:167
IPV4_GET_RAW_IPDST_U32
#define IPV4_GET_RAW_IPDST_U32(ip4h)
Definition: decode-ipv4.h:109
hashword
uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval)
Definition: util-hash-lookup3.c:174
FLOW_STATE_ESTABLISHED
@ FLOW_STATE_ESTABLISHED
Definition: flow.h:506
flow-util.h
FBLOCK_LOCK
#define FBLOCK_LOCK(fb)
Definition: flow-hash.h:73
FlowLookupStruct_::dtv
DecodeThreadVars * dtv
Definition: flow.h:546
DecodeThreadVars_::counter_flow_icmp4
uint16_t counter_flow_icmp4
Definition: decode.h:726
Flow_::startts
SCTime_t startts
Definition: flow.h:496
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:455
stream-tcp.h
FlowHashKey6_::proto
uint16_t proto
Definition: flow-hash.c:103
FlowKey_::src
Address src
Definition: flow.h:312
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
PKT_DROP_REASON_FLOW_MEMCAP
@ PKT_DROP_REASON_FLOW_MEMCAP
Definition: decode.h:395
FlowCnf_::hash_size
uint32_t hash_size
Definition: flow.h:293
FlowAddress_::address_un_data32
uint32_t address_un_data32[4]
Definition: flow.h:321
FlowSpareGetFromPool
FlowQueuePrivate FlowSpareGetFromPool(void)
Definition: flow-spare-pool.c:127
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:269
Packet_::pcap_cnt
uint64_t pcap_cnt
Definition: decode.h:594
DecodeThreadVars_::counter_flow_spare_sync_avg
uint16_t counter_flow_spare_sync_avg
Definition: decode.h:738
Flow_::proto
uint8_t proto
Definition: flow.h:379
Packet_::flags
uint32_t flags
Definition: decode.h:463
FlowKeyGetHash
uint32_t FlowKeyGetHash(FlowKey *fk)
Definition: flow-hash.c:282
threads.h
ICMPV4_DEST_UNREACH_IS_VALID
#define ICMPV4_DEST_UNREACH_IS_VALID(p)
Definition: decode-icmpv4.h:267
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:357
Flow_::protomap
uint8_t protomap
Definition: flow.h:451
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:333
FlowProtoTimeout_
Definition: flow.h:519
FLOWLOCK_TRYWRLOCK
#define FLOWLOCK_TRYWRLOCK(fb)
Definition: flow.h:271
PKT_WANTS_FLOW
#define PKT_WANTS_FLOW
Definition: decode.h:1033
flow-hash.h
FlowHashKey6_::u32
const uint32_t u32[11]
Definition: flow-hash.c:107
FlowHashKey4_::u32
const uint32_t u32[5]
Definition: flow-hash.c:94
FlowLookupStruct_
Definition: flow.h:543
Flow_::vlan_id
uint16_t vlan_id[2]
Definition: flow.h:381
FlowHashKey4_::vlan_id
uint16_t vlan_id[2]
Definition: flow-hash.c:92
FlowHashKey4
struct FlowHashKey4_ FlowHashKey4
FBLOCK_TRYLOCK
#define FBLOCK_TRYLOCK(fb)
Definition: flow-hash.h:74
TcpStreamCnf_
Definition: stream-tcp.h:43
DecodeThreadVars_::counter_flow_tcp
uint16_t counter_flow_tcp
Definition: decode.h:724
Address_::address_un_data32
uint32_t address_un_data32[4]
Definition: decode.h:117
proto
uint8_t proto
Definition: decode-template.h:0
Flow_::dp
Port dp
Definition: flow.h:373
stream_config
TcpStreamCnf stream_config
Definition: stream-tcp.c:115
FlowQueuePrivate_::len
uint32_t len
Definition: flow-queue.h:44
Flow_::protoctx
void * protoctx
Definition: flow.h:447
Flow_::icmp_s
struct Flow_::@116::@122 icmp_s
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:97
DecodeThreadVars_::counter_flow_get_used
uint16_t counter_flow_get_used
Definition: decode.h:729
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:272
Flow_::flow_state
FlowStateType flow_state
Definition: flow.h:418
DecodeThreadVars_::counter_flow_spare_sync_empty
uint16_t counter_flow_spare_sync_empty
Definition: decode.h:736
DecodeThreadVars_::counter_flow_tcp_reuse
uint16_t counter_flow_tcp_reuse
Definition: decode.h:728
DecodeThreadVars_::counter_flow_total
uint16_t counter_flow_total
Definition: decode.h:722
Packet_::icmp_s
struct Packet_::@32::@42 icmp_s
FLOW_CHECK_MEMCAP
#define FLOW_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition: flow-util.h:144
FlowLookupStruct_::emerg_spare_sync_stamp
uint32_t emerg_spare_sync_stamp
Definition: flow.h:548
TcpSessionPacketSsnReuse
int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, const void *tcp_ssn)
Definition: stream-tcp.c:5629
PKT_IS_TCP
#define PKT_IS_TCP(p)
Definition: decode.h:247
flow-spare-pool.h
DecodeThreadVars_::counter_flow_spare_sync
uint16_t counter_flow_spare_sync
Definition: decode.h:735
Flow_::dst
FlowAddress dst
Definition: flow.h:360
Flow_::fb
struct FlowBucket_ * fb
Definition: flow.h:494
FlowHashKey6_::ports
uint16_t ports[2]
Definition: flow-hash.c:102
decode.h
util-debug.h
STREAM_PKT_FLAG_TCP_PORT_REUSE
#define STREAM_PKT_FLAG_TCP_PORT_REUSE
Definition: stream-tcp-private.h:316
FLOW_GET_NEW_TRIES
#define FLOW_GET_NEW_TRIES
Definition: flow-hash.c:1083
STATSADDUI64
#define STATSADDUI64(cnt, value)
Definition: flow-hash.c:1134
SCTIME_FROM_TIMESPEC
#define SCTIME_FROM_TIMESPEC(ts)
Definition: util-time.h:76
Packet_::ts
SCTime_t ts
Definition: decode.h:471
ICMPV4_GET_EMB_IPV4
#define ICMPV4_GET_EMB_IPV4(p)
Definition: decode-icmpv4.h:252
util-exception-policy.h
Flow_::lastts
SCTime_t lastts
Definition: flow.h:416
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:269
SC_ATOMIC_EXTERN
SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx)
FlowKey_::recursion_level
uint8_t recursion_level
Definition: flow.h:315
ICMPV4Vars_::emb_dport
uint16_t emb_dport
Definition: decode-icmpv4.h:204
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:57
Flow_::flow_end_flags
uint8_t flow_end_flags
Definition: flow.h:453
FlowStorageSize
unsigned int FlowStorageSize(void)
Definition: flow-storage.c:35
Packet_::sp
Port sp
Definition: decode.h:435
FlowHashKey6
struct FlowHashKey6_ FlowHashKey6
util-time.h
FlowQueuePrivateGetFromTop
Flow * FlowQueuePrivateGetFromTop(FlowQueuePrivate *fqc)
Definition: flow-queue.c:151
app-layer-parser.h
ThreadVars_::id
int id
Definition: threadvars.h:86
BUG_ON
#define BUG_ON(x)
Definition: suricata-common.h:289
FlowGetExistingFlowFromHash
Flow * FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash)
Look for existing Flow using a FlowKey.
Definition: flow-hash.c:1039
FlowThreadId
uint16_t FlowThreadId
Definition: flow.h:336
FlowKey_::sp
Port sp
Definition: flow.h:313
FlowTimeoutsEmergency
void FlowTimeoutsEmergency(void)
Definition: flow-manager.c:105
FlowGetProtoMapping
uint8_t FlowGetProtoMapping(uint8_t proto)
Function to map the protocol to the defined FLOW_PROTO_* enumeration.
Definition: flow-util.c:98
Packet_
Definition: decode.h:428
ESP_GET_SPI
#define ESP_GET_SPI(p)
Get the spi field off a packet.
Definition: decode-esp.h:32
FlowGetExistingFlowFromFlowId
Flow * FlowGetExistingFlowFromFlowId(int64_t flow_id)
Look for existing Flow using a flow id value.
Definition: flow-hash.c:920
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:531
Port
uint16_t Port
Definition: decode.h:229
FLOW_END_FLAG_EMERGENCY
#define FLOW_END_FLAG_EMERGENCY
Definition: flow.h:241
FBLOCK_UNLOCK
#define FBLOCK_UNLOCK(fb)
Definition: flow-hash.h:75
FlowKey_::vlan_id
uint16_t vlan_id[2]
Definition: flow.h:316
SCTime_t
Definition: util-time.h:40
FlowHashKey4_
Definition: flow-hash.c:85
FlowClearMemory
int FlowClearMemory(Flow *f, uint8_t proto_map)
Function clear the flow memory before queueing it to spare flow queue.
Definition: flow.c:1107
flow_timeouts_delta
FlowProtoTimeout flow_timeouts_delta[FLOW_PROTO_MAX]
Definition: flow.c:96
FlowCnf_::hash_rand
uint32_t hash_rand
Definition: flow.h:292
FlowHashKey4_::addrs
uint32_t addrs[2]
Definition: flow-hash.c:88
output-flow.h
FlowWakeupFlowManagerThread
#define FlowWakeupFlowManagerThread()
Definition: flow-manager.h:30
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
FlowHashKey6_
Definition: flow-hash.c:98
flow-timeout.h
Address_::address
union Address_::@31 address
Flow_::flow_hash
uint32_t flow_hash
Definition: flow.h:407
RunmodeIsUnittests
int RunmodeIsUnittests(void)
Definition: suricata.c:232
Flow_::icmp_d
struct Flow_::@118::@124 icmp_d
FlowUpdateState
void FlowUpdateState(Flow *f, const enum FlowState s)
Definition: flow.c:1172
Flow_::src
FlowAddress src
Definition: flow.h:360
Flow_::next
struct Flow_ * next
Definition: flow.h:402
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:33
FlowHashKey6_::src
uint32_t src[4]
Definition: flow-hash.c:101
FlowLookupStruct_::spare_queue
FlowQueuePrivate spare_queue
Definition: flow.h:545
FlowGetIpPairProtoHash
uint32_t FlowGetIpPairProtoHash(const Packet *p)
Definition: flow-hash.c:111
flow_hash
FlowBucket * flow_hash
Definition: flow-hash.c:57
Packet_::icmpv4vars
ICMPV4Vars icmpv4vars
Definition: decode.h:546
flow-storage.h
TH_SYN
#define TH_SYN
Definition: decode-tcp.h:35
FLOW_STATE_NEW
@ FLOW_STATE_NEW
Definition: flow.h:505
DecodeThreadVars_::counter_flow_spare_sync_incomplete
uint16_t counter_flow_spare_sync_incomplete
Definition: decode.h:737
flow-manager.h
suricata-common.h
IPV4_GET_RAW_IPSRC_U32
#define IPV4_GET_RAW_IPSRC_U32(ip4h)
Definition: decode-ipv4.h:107
FLOW_IPV6
#define FLOW_IPV6
Definition: flow.h:99
DecodeThreadVars_::counter_flow_icmp6
uint16_t counter_flow_icmp6
Definition: decode.h:727
Packet_::tcph
TCPHdr * tcph
Definition: decode.h:553
flow_config
FlowConfig flow_config
Definition: flow.c:99
FlowKey_::dst
Address dst
Definition: flow.h:312
SCTIME_SECS
#define SCTIME_SECS(t)
Definition: util-time.h:57
FlowHashKey4_::recur
uint16_t recur
Definition: flow-hash.c:91
util-hash-lookup3.h
FlowGetFlowFromHash
Flow * FlowGetFlowFromHash(ThreadVars *tv, FlowLookupStruct *fls, Packet *p, Flow **dest)
Get Flow for packet.
Definition: flow-hash.c:798
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:32
PKT_IS_ICMPV4
#define PKT_IS_ICMPV4(p)
Definition: decode.h:249
FlowHashKey6_::dst
uint32_t dst[4]
Definition: flow-hash.c:101
TcpStreamCnf_::midstream
bool midstream
Definition: stream-tcp.h:59
Flow_::esp
struct Flow_::@116::@123 esp
FlowCnf_::memcap_policy
enum ExceptionPolicy memcap_policy
Definition: flow.h:304
StatsAddUI64
void StatsAddUI64(ThreadVars *tv, uint16_t id, uint64_t x)
Adds a value of type uint64_t to the local counter.
Definition: counters.c:146
ICMPV4_IS_ERROR_MSG
#define ICMPV4_IS_ERROR_MSG(p)
Definition: decode-icmpv4.h:284
g_vlan_mask
uint16_t g_vlan_mask
Definition: suricata.c:197
Packet_::flow_hash
uint32_t flow_hash
Definition: decode.h:469
FlowKey_::proto
uint8_t proto
Definition: flow.h:314
FLOW_STATE_CLOSED
@ FLOW_STATE_CLOSED
Definition: flow.h:507
FlowHashKey4_::proto
uint16_t proto
Definition: flow-hash.c:90
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:664
FlowGetFromFlowKey
Flow * FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
Get or create a Flow using a FlowKey.
Definition: flow-hash.c:978
Flow_::flags
uint32_t flags
Definition: flow.h:427
Packet_::recursion_level
uint8_t recursion_level
Definition: decode.h:453
DecodeThreadVars_::output_flow_thread_data
void * output_flow_thread_data
Definition: decode.h:744
FlowKey_
Definition: flow.h:311
Packet_::udph
UDPHdr * udph
Definition: decode.h:555
FLOW_EMERGENCY
#define FLOW_EMERGENCY
Definition: flow-private.h:37
STREAM_PKT_FLAG_SET
#define STREAM_PKT_FLAG_SET(p, f)
Definition: stream-tcp-private.h:318
FlowHashKey6_::vlan_id
uint16_t vlan_id[2]
Definition: flow-hash.c:105
Address_::family
char family
Definition: decode.h:115
Packet_::dst
Address dst
Definition: decode.h:433
FLOW_PROTO_MAX
@ FLOW_PROTO_MAX
Definition: flow-private.h:76
DecodeThreadVars_::counter_flow_memcap
uint16_t counter_flow_memcap
Definition: decode.h:719
FLOW_END_FLAG_TIMEOUT
#define FLOW_END_FLAG_TIMEOUT
Definition: flow.h:242
Flow_::sp
Port sp
Definition: flow.h:362
ICMPV4Vars_::emb_sport
uint16_t emb_sport
Definition: decode-icmpv4.h:203
Packet_::ip6h
IPV6Hdr * ip6h
Definition: decode.h:533
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:376
flow.h
FlowQueuePrivateAppendFlow
void FlowQueuePrivateAppendFlow(FlowQueuePrivate *fqc, Flow *f)
Definition: flow-queue.c:65
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:54
Packet_::dp
Port dp
Definition: decode.h:443
FLOW_END_FLAG_FORCED
#define FLOW_END_FLAG_FORCED
Definition: flow.h:243
Flow_::timeout_at
uint32_t timeout_at
Definition: flow.h:397
FlowKey_::dp
Port dp
Definition: flow.h:313
FlowInit
void FlowInit(Flow *f, const Packet *p)
Definition: flow-util.c:146
FlowSetupPacket
void FlowSetupPacket(Packet *p)
prepare packet for a life with flow Set PKT_WANTS_FLOW flag to incidate workers should do a flow look...
Definition: flow-hash.c:479
Packet_::src
Address src
Definition: decode.h:432
output.h
Packet_::icmp_d
struct Packet_::@34::@43 icmp_d
Flow_::thread_id
FlowThreadId thread_id[2]
Definition: flow.h:400
SC_ATOMIC_OR
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
Definition: util-atomic.h:351