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