suricata
flow-hash.c
Go to the documentation of this file.
1 /* Copyright (C) 2007-2013 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 "app-layer-parser.h"
40 
41 #include "util-time.h"
42 #include "util-debug.h"
43 
44 #include "util-hash-lookup3.h"
45 
46 #include "conf.h"
47 #include "output.h"
48 #include "output-flow.h"
49 
50 #define FLOW_DEFAULT_FLOW_PRUNE 5
51 
52 FlowBucket *flow_hash;
53 SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx);
54 SC_ATOMIC_EXTERN(unsigned int, flow_flags);
55 
56 static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv);
57 
58 /** \brief compare two raw ipv6 addrs
59  *
60  * \note we don't care about the real ipv6 ip's, this is just
61  * to consistently fill the FlowHashKey6 struct, without all
62  * the SCNtohl calls.
63  *
64  * \warning do not use elsewhere unless you know what you're doing.
65  * detect-engine-address-ipv6.c's AddressIPv6GtU32 is likely
66  * what you are looking for.
67  */
68 static inline int FlowHashRawAddressIPv6GtU32(const uint32_t *a, const uint32_t *b)
69 {
70  int i;
71 
72  for (i = 0; i < 4; i++) {
73  if (a[i] > b[i])
74  return 1;
75  if (a[i] < b[i])
76  break;
77  }
78 
79  return 0;
80 }
81 
82 typedef struct FlowHashKey4_ {
83  union {
84  struct {
85  uint32_t addrs[2];
86  uint16_t ports[2];
87  uint16_t proto; /**< u16 so proto and recur add up to u32 */
88  uint16_t recur; /**< u16 so proto and recur add up to u32 */
89  uint16_t vlan_id[2];
90  };
91  const uint32_t u32[5];
92  };
94 
95 typedef struct FlowHashKey6_ {
96  union {
97  struct {
98  uint32_t src[4], dst[4];
99  uint16_t ports[2];
100  uint16_t proto; /**< u16 so proto and recur add up to u32 */
101  uint16_t recur; /**< u16 so proto and recur add up to u32 */
102  uint16_t vlan_id[2];
103  };
104  const uint32_t u32[11];
105  };
107 
108 /* calculate the hash key for this packet
109  *
110  * we're using:
111  * hash_rand -- set at init time
112  * source port
113  * destination port
114  * source address
115  * destination address
116  * recursion level -- for tunnels, make sure different tunnel layers can
117  * never get mixed up.
118  *
119  * For ICMP we only consider UNREACHABLE errors atm.
120  */
121 static inline uint32_t FlowGetHash(const Packet *p)
122 {
123  uint32_t hash = 0;
124 
125  if (p->ip4h != NULL) {
126  if (p->tcph != NULL || p->udph != NULL) {
127  FlowHashKey4 fhk;
128 
129  int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
130  fhk.addrs[1-ai] = p->src.addr_data32[0];
131  fhk.addrs[ai] = p->dst.addr_data32[0];
132 
133  const int pi = (p->sp > p->dp);
134  fhk.ports[1-pi] = p->sp;
135  fhk.ports[pi] = p->dp;
136 
137  fhk.proto = (uint16_t)p->proto;
138  fhk.recur = (uint16_t)p->recursion_level;
139  /* g_vlan_mask sets the vlan_ids to 0 if vlan.use-for-tracking
140  * is disabled. */
141  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
142  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
143 
144  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
145 
146  } else if (ICMPV4_DEST_UNREACH_IS_VALID(p)) {
147  uint32_t psrc = IPV4_GET_RAW_IPSRC_U32(ICMPV4_GET_EMB_IPV4(p));
148  uint32_t pdst = IPV4_GET_RAW_IPDST_U32(ICMPV4_GET_EMB_IPV4(p));
149  FlowHashKey4 fhk;
150 
151  const int ai = (psrc > pdst);
152  fhk.addrs[1-ai] = psrc;
153  fhk.addrs[ai] = pdst;
154 
155  const int pi = (p->icmpv4vars.emb_sport > p->icmpv4vars.emb_dport);
156  fhk.ports[1-pi] = p->icmpv4vars.emb_sport;
157  fhk.ports[pi] = p->icmpv4vars.emb_dport;
158 
159  fhk.proto = (uint16_t)ICMPV4_GET_EMB_PROTO(p);
160  fhk.recur = (uint16_t)p->recursion_level;
161  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
162  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
163 
164  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
165 
166  } else {
167  FlowHashKey4 fhk;
168  const int ai = (p->src.addr_data32[0] > p->dst.addr_data32[0]);
169  fhk.addrs[1-ai] = p->src.addr_data32[0];
170  fhk.addrs[ai] = p->dst.addr_data32[0];
171  fhk.ports[0] = 0xfeed;
172  fhk.ports[1] = 0xbeef;
173  fhk.proto = (uint16_t)p->proto;
174  fhk.recur = (uint16_t)p->recursion_level;
175  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
176  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
177 
178  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
179  }
180  } else if (p->ip6h != NULL) {
181  FlowHashKey6 fhk;
182  if (FlowHashRawAddressIPv6GtU32(p->src.addr_data32, p->dst.addr_data32)) {
183  fhk.src[0] = p->src.addr_data32[0];
184  fhk.src[1] = p->src.addr_data32[1];
185  fhk.src[2] = p->src.addr_data32[2];
186  fhk.src[3] = p->src.addr_data32[3];
187  fhk.dst[0] = p->dst.addr_data32[0];
188  fhk.dst[1] = p->dst.addr_data32[1];
189  fhk.dst[2] = p->dst.addr_data32[2];
190  fhk.dst[3] = p->dst.addr_data32[3];
191  } else {
192  fhk.src[0] = p->dst.addr_data32[0];
193  fhk.src[1] = p->dst.addr_data32[1];
194  fhk.src[2] = p->dst.addr_data32[2];
195  fhk.src[3] = p->dst.addr_data32[3];
196  fhk.dst[0] = p->src.addr_data32[0];
197  fhk.dst[1] = p->src.addr_data32[1];
198  fhk.dst[2] = p->src.addr_data32[2];
199  fhk.dst[3] = p->src.addr_data32[3];
200  }
201 
202  const int pi = (p->sp > p->dp);
203  fhk.ports[1-pi] = p->sp;
204  fhk.ports[pi] = p->dp;
205  fhk.proto = (uint16_t)p->proto;
206  fhk.recur = (uint16_t)p->recursion_level;
207  fhk.vlan_id[0] = p->vlan_id[0] & g_vlan_mask;
208  fhk.vlan_id[1] = p->vlan_id[1] & g_vlan_mask;
209 
210  hash = hashword(fhk.u32, 11, flow_config.hash_rand);
211  }
212 
213  return hash;
214 }
215 
216 /**
217  * Basic hashing function for FlowKey
218  *
219  * \note Function only used for bypass and TCP or UDP flows
220  *
221  * \note this is only used at start to create Flow from pinned maps
222  * so fairness is not an issue
223  */
224 uint32_t FlowKeyGetHash(FlowKey *fk)
225 {
226  uint32_t hash = 0;
227 
228  if (fk->src.family == AF_INET) {
229  FlowHashKey4 fhk;
230  int ai = (fk->src.address.address_un_data32[0] > fk->dst.address.address_un_data32[0]);
231  fhk.addrs[1-ai] = fk->src.address.address_un_data32[0];
232  fhk.addrs[ai] = fk->dst.address.address_un_data32[0];
233 
234  const int pi = (fk->sp > fk->dp);
235  fhk.ports[1-pi] = fk->sp;
236  fhk.ports[pi] = fk->dp;
237 
238  fhk.proto = (uint16_t)fk->proto;
239  fhk.recur = (uint16_t)fk->recursion_level;
240  fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
241  fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
242 
243  hash = hashword(fhk.u32, 5, flow_config.hash_rand);
244  } else {
245  FlowHashKey6 fhk;
246  if (FlowHashRawAddressIPv6GtU32(fk->src.address.address_un_data32,
248  fhk.src[0] = fk->src.address.address_un_data32[0];
249  fhk.src[1] = fk->src.address.address_un_data32[1];
250  fhk.src[2] = fk->src.address.address_un_data32[2];
251  fhk.src[3] = fk->src.address.address_un_data32[3];
252  fhk.dst[0] = fk->dst.address.address_un_data32[0];
253  fhk.dst[1] = fk->dst.address.address_un_data32[1];
254  fhk.dst[2] = fk->dst.address.address_un_data32[2];
255  fhk.dst[3] = fk->dst.address.address_un_data32[3];
256  } else {
257  fhk.src[0] = fk->dst.address.address_un_data32[0];
258  fhk.src[1] = fk->dst.address.address_un_data32[1];
259  fhk.src[2] = fk->dst.address.address_un_data32[2];
260  fhk.src[3] = fk->dst.address.address_un_data32[3];
261  fhk.dst[0] = fk->src.address.address_un_data32[0];
262  fhk.dst[1] = fk->src.address.address_un_data32[1];
263  fhk.dst[2] = fk->src.address.address_un_data32[2];
264  fhk.dst[3] = fk->src.address.address_un_data32[3];
265  }
266 
267  const int pi = (fk->sp > fk->dp);
268  fhk.ports[1-pi] = fk->sp;
269  fhk.ports[pi] = fk->dp;
270  fhk.proto = (uint16_t)fk->proto;
271  fhk.recur = (uint16_t)fk->recursion_level;
272  fhk.vlan_id[0] = fk->vlan_id[0] & g_vlan_mask;
273  fhk.vlan_id[1] = fk->vlan_id[1] & g_vlan_mask;
274 
275  hash = hashword(fhk.u32, 11, flow_config.hash_rand);
276  }
277  return hash;
278 }
279 
280 static inline bool CmpAddrs(const uint32_t addr1[4], const uint32_t addr2[4])
281 {
282  return addr1[0] == addr2[0] && addr1[1] == addr2[1] &&
283  addr1[2] == addr2[2] && addr1[3] == addr2[3];
284 }
285 
286 static inline bool CmpAddrsAndPorts(const uint32_t src1[4],
287  const uint32_t dst1[4], Port src_port1, Port dst_port1,
288  const uint32_t src2[4], const uint32_t dst2[4], Port src_port2,
289  Port dst_port2)
290 {
291  /* Compare the source and destination addresses. If they are not equal,
292  * compare the first source address with the second destination address,
293  * and vice versa. Likewise for ports. */
294  return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
295  src_port1 == src_port2 && dst_port1 == dst_port2) ||
296  (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
297  src_port1 == dst_port2 && dst_port1 == src_port2);
298 }
299 
300 static inline bool CmpVlanIds(const uint16_t vlan_id1[2], const uint16_t vlan_id2[2])
301 {
302  return ((vlan_id1[0] ^ vlan_id2[0]) & g_vlan_mask) == 0 &&
303  ((vlan_id1[1] ^ vlan_id2[1]) & g_vlan_mask) == 0;
304 }
305 
306 /* Since two or more flows can have the same hash key, we need to compare
307  * the flow with the current packet or flow key. */
308 static inline bool CmpFlowPacket(const Flow *f, const Packet *p)
309 {
310  const uint32_t *f_src = f->src.address.address_un_data32;
311  const uint32_t *f_dst = f->dst.address.address_un_data32;
312  const uint32_t *p_src = p->src.address.address_un_data32;
313  const uint32_t *p_dst = p->dst.address.address_un_data32;
314  return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, p_src, p_dst, p->sp,
315  p->dp) && f->proto == p->proto &&
316  f->recursion_level == p->recursion_level &&
317  CmpVlanIds(f->vlan_id, p->vlan_id);
318 }
319 
320 static inline bool CmpFlowKey(const Flow *f, const FlowKey *k)
321 {
322  const uint32_t *f_src = f->src.address.address_un_data32;
323  const uint32_t *f_dst = f->dst.address.address_un_data32;
324  const uint32_t *k_src = k->src.address.address_un_data32;
325  const uint32_t *k_dst = k->dst.address.address_un_data32;
326  return CmpAddrsAndPorts(f_src, f_dst, f->sp, f->dp, k_src, k_dst, k->sp,
327  k->dp) && f->proto == k->proto &&
328  f->recursion_level == k->recursion_level &&
329  CmpVlanIds(f->vlan_id, k->vlan_id);
330 }
331 
332 static inline bool CmpAddrsAndICMPTypes(const uint32_t src1[4],
333  const uint32_t dst1[4], uint8_t icmp_s_type1, uint8_t icmp_d_type1,
334  const uint32_t src2[4], const uint32_t dst2[4], uint8_t icmp_s_type2,
335  uint8_t icmp_d_type2)
336 {
337  /* Compare the source and destination addresses. If they are not equal,
338  * compare the first source address with the second destination address,
339  * and vice versa. Likewise for icmp types. */
340  return (CmpAddrs(src1, src2) && CmpAddrs(dst1, dst2) &&
341  icmp_s_type1 == icmp_s_type2 && icmp_d_type1 == icmp_d_type2) ||
342  (CmpAddrs(src1, dst2) && CmpAddrs(dst1, src2) &&
343  icmp_s_type1 == icmp_d_type2 && icmp_d_type1 == icmp_s_type2);
344 }
345 
346 static inline bool CmpFlowICMPPacket(const Flow *f, const Packet *p)
347 {
348  const uint32_t *f_src = f->src.address.address_un_data32;
349  const uint32_t *f_dst = f->dst.address.address_un_data32;
350  const uint32_t *p_src = p->src.address.address_un_data32;
351  const uint32_t *p_dst = p->dst.address.address_un_data32;
352  return CmpAddrsAndICMPTypes(f_src, f_dst, f->icmp_s.type,
353  f->icmp_d.type, p_src, p_dst, p->icmp_s.type, p->icmp_d.type) &&
354  f->proto == p->proto && f->recursion_level == p->recursion_level &&
355  CmpVlanIds(f->vlan_id, p->vlan_id);
356 }
357 
358 /**
359  * \brief See if a ICMP packet belongs to a flow by comparing the embedded
360  * packet in the ICMP error packet to the flow.
361  *
362  * \param f flow
363  * \param p ICMP packet
364  *
365  * \retval 1 match
366  * \retval 0 no match
367  */
368 static inline int FlowCompareICMPv4(Flow *f, const Packet *p)
369 {
371  /* first check the direction of the flow, in other words, the client ->
372  * server direction as it's most likely the ICMP error will be a
373  * response to the clients traffic */
374  if ((f->src.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) &&
375  (f->dst.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) &&
376  f->sp == p->icmpv4vars.emb_sport &&
377  f->dp == p->icmpv4vars.emb_dport &&
378  f->proto == ICMPV4_GET_EMB_PROTO(p) &&
379  f->recursion_level == p->recursion_level &&
380  f->vlan_id[0] == p->vlan_id[0] &&
381  f->vlan_id[1] == p->vlan_id[1])
382  {
383  return 1;
384 
385  /* check the less likely case where the ICMP error was a response to
386  * a packet from the server. */
387  } else if ((f->dst.addr_data32[0] == IPV4_GET_RAW_IPSRC_U32( ICMPV4_GET_EMB_IPV4(p) )) &&
388  (f->src.addr_data32[0] == IPV4_GET_RAW_IPDST_U32( ICMPV4_GET_EMB_IPV4(p) )) &&
389  f->dp == p->icmpv4vars.emb_sport &&
390  f->sp == p->icmpv4vars.emb_dport &&
391  f->proto == ICMPV4_GET_EMB_PROTO(p) &&
392  f->recursion_level == p->recursion_level &&
393  f->vlan_id[0] == p->vlan_id[0] &&
394  f->vlan_id[1] == p->vlan_id[1])
395  {
396  return 1;
397  }
398 
399  /* no match, fall through */
400  } else {
401  /* just treat ICMP as a normal proto for now */
402  return CmpFlowICMPPacket(f, p);
403  }
404 
405  return 0;
406 }
407 
409 {
410  p->flags |= PKT_WANTS_FLOW;
411  p->flow_hash = FlowGetHash(p);
412 }
413 
414 int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, void *tcp_ssn);
415 
416 static inline int FlowCompare(Flow *f, const Packet *p)
417 {
418  if (p->proto == IPPROTO_ICMP) {
419  return FlowCompareICMPv4(f, p);
420  } else if (p->proto == IPPROTO_TCP) {
421  if (CmpFlowPacket(f, p) == 0)
422  return 0;
423 
424  /* if this session is 'reused', we don't return it anymore,
425  * so return false on the compare */
426  if (f->flags & FLOW_TCP_REUSED)
427  return 0;
428 
429  return 1;
430  } else {
431  return CmpFlowPacket(f, p);
432  }
433 }
434 
435 /**
436  * \brief Check if we should create a flow based on a packet
437  *
438  * We use this check to filter out flow creation based on:
439  * - ICMP error messages
440  *
441  * \param p packet
442  * \retval 1 true
443  * \retval 0 false
444  */
445 static inline int FlowCreateCheck(const Packet *p)
446 {
447  if (PKT_IS_ICMPV4(p)) {
448  if (ICMPV4_IS_ERROR_MSG(p)) {
449  return 0;
450  }
451  }
452 
453  return 1;
454 }
455 
456 static inline void FlowUpdateCounter(ThreadVars *tv, DecodeThreadVars *dtv,
457  uint8_t proto)
458 {
459 #ifdef UNITTESTS
460  if (tv && dtv) {
461 #endif
462  switch (proto){
463  case IPPROTO_UDP:
465  break;
466  case IPPROTO_TCP:
468  break;
469  case IPPROTO_ICMP:
471  break;
472  case IPPROTO_ICMPV6:
474  break;
475  }
476 #ifdef UNITTESTS
477  }
478 #endif
479 }
480 
481 /**
482  * \brief Get a new flow
483  *
484  * Get a new flow. We're checking memcap first and will try to make room
485  * if the memcap is reached.
486  *
487  * \param tv thread vars
488  * \param dtv decode thread vars (for flow log api thread data)
489  *
490  * \retval f *LOCKED* flow on succes, NULL on error.
491  */
492 static Flow *FlowGetNew(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p)
493 {
494  Flow *f = NULL;
495 
496  if (FlowCreateCheck(p) == 0) {
497  return NULL;
498  }
499 
500  /* get a flow from the spare queue */
502  if (f == NULL) {
503  /* If we reached the max memcap, we get a used flow */
504  if (!(FLOW_CHECK_MEMCAP(sizeof(Flow) + FlowStorageSize()))) {
505  /* declare state of emergency */
506  if (!(SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)) {
507  SC_ATOMIC_OR(flow_flags, FLOW_EMERGENCY);
508 
510 
511  /* under high load, waking up the flow mgr each time leads
512  * to high cpu usage. Flows are not timed out much faster if
513  * we check a 1000 times a second. */
515  }
516 
517  f = FlowGetUsedFlow(tv, dtv);
518  if (f == NULL) {
519  /* max memcap reached, so increments the counter */
520  if (tv != NULL && dtv != NULL) {
522  }
523 
524  /* very rare, but we can fail. Just giving up */
525  return NULL;
526  }
527 
528  /* freed a flow, but it's unlocked */
529  } else {
530  /* now see if we can alloc a new flow */
531  f = FlowAlloc();
532  if (f == NULL) {
533  if (tv != NULL && dtv != NULL) {
535  }
536  return NULL;
537  }
538 
539  /* flow is initialized but *unlocked* */
540  }
541  } else {
542  /* flow has been recycled before it went into the spare queue */
543 
544  /* flow is initialized (recylced) but *unlocked* */
545  }
546 
547  FLOWLOCK_WRLOCK(f);
548  FlowUpdateCounter(tv, dtv, p->proto);
549  return f;
550 }
551 
552 static Flow *TcpReuseReplace(ThreadVars *tv, DecodeThreadVars *dtv,
553  FlowBucket *fb, Flow *old_f,
554  const uint32_t hash, const Packet *p)
555 {
556  /* tag flow as reused so future lookups won't find it */
557  old_f->flags |= FLOW_TCP_REUSED;
558  /* get some settings that we move over to the new flow */
559  FlowThreadId thread_id[2] = { old_f->thread_id[0], old_f->thread_id[1] };
560 
561  /* since fb lock is still held this flow won't be found until we are done */
562  FLOWLOCK_UNLOCK(old_f);
563 
564  /* Get a new flow. It will be either a locked flow or NULL */
565  Flow *f = FlowGetNew(tv, dtv, p);
566  if (f == NULL) {
567  return NULL;
568  }
569 
570  /* flow is locked */
571 
572  /* put at the start of the list */
573  f->hnext = fb->head;
574  fb->head->hprev = f;
575  fb->head = f;
576 
577  /* initialize and return */
578  FlowInit(f, p);
579  f->flow_hash = hash;
580  f->fb = fb;
581 
582  f->thread_id[0] = thread_id[0];
583  f->thread_id[1] = thread_id[1];
584  return f;
585 }
586 
587 /** \brief Get Flow for packet
588  *
589  * Hash retrieval function for flows. Looks up the hash bucket containing the
590  * flow pointer. Then compares the packet with the found flow to see if it is
591  * the flow we need. If it isn't, walk the list until the right flow is found.
592  *
593  * If the flow is not found or the bucket was emtpy, a new flow is taken from
594  * the queue. FlowDequeue() will alloc new flows as long as we stay within our
595  * memcap limit.
596  *
597  * The p->flow pointer is updated to point to the flow.
598  *
599  * \param tv thread vars
600  * \param dtv decode thread vars (for flow log api thread data)
601  *
602  * \retval f *LOCKED* flow or NULL
603  */
605 {
606  Flow *f = NULL;
607 
608  /* get our hash bucket and lock it */
609  const uint32_t hash = p->flow_hash;
610  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
611  FBLOCK_LOCK(fb);
612 
613  SCLogDebug("fb %p fb->head %p", fb, fb->head);
614 
615  /* see if the bucket already has a flow */
616  if (fb->head == NULL) {
617  f = FlowGetNew(tv, dtv, p);
618  if (f == NULL) {
619  FBLOCK_UNLOCK(fb);
620  return NULL;
621  }
622 
623  /* flow is locked */
624  fb->head = f;
625  fb->tail = f;
626 
627  /* got one, now lock, initialize and return */
628  FlowInit(f, p);
629  f->flow_hash = hash;
630  f->fb = fb;
632 
633  FlowReference(dest, f);
634 
635  FBLOCK_UNLOCK(fb);
636  return f;
637  }
638 
639  /* ok, we have a flow in the bucket. Let's find out if it is our flow */
640  f = fb->head;
641 
642  /* see if this is the flow we are looking for */
643  if (FlowCompare(f, p) == 0) {
644  Flow *pf = NULL; /* previous flow */
645 
646  while (f) {
647  pf = f;
648  f = f->hnext;
649 
650  if (f == NULL) {
651  f = pf->hnext = FlowGetNew(tv, dtv, p);
652  if (f == NULL) {
653  FBLOCK_UNLOCK(fb);
654  return NULL;
655  }
656  fb->tail = f;
657 
658  /* flow is locked */
659 
660  f->hprev = pf;
661 
662  /* initialize and return */
663  FlowInit(f, p);
664  f->flow_hash = hash;
665  f->fb = fb;
667 
668  FlowReference(dest, f);
669 
670  FBLOCK_UNLOCK(fb);
671  return f;
672  }
673 
674  if (FlowCompare(f, p) != 0) {
675  /* we found our flow, lets put it on top of the
676  * hash list -- this rewards active flows */
677  if (f->hnext) {
678  f->hnext->hprev = f->hprev;
679  }
680  if (f->hprev) {
681  f->hprev->hnext = f->hnext;
682  }
683  if (f == fb->tail) {
684  fb->tail = f->hprev;
685  }
686 
687  f->hnext = fb->head;
688  f->hprev = NULL;
689  fb->head->hprev = f;
690  fb->head = f;
691 
692  /* found our flow, lock & return */
693  FLOWLOCK_WRLOCK(f);
694  if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) {
695  f = TcpReuseReplace(tv, dtv, fb, f, hash, p);
696  if (f == NULL) {
697  FBLOCK_UNLOCK(fb);
698  return NULL;
699  }
700  }
701 
702  FlowReference(dest, f);
703 
704  FBLOCK_UNLOCK(fb);
705  return f;
706  }
707  }
708  }
709 
710  /* lock & return */
711  FLOWLOCK_WRLOCK(f);
712  if (unlikely(TcpSessionPacketSsnReuse(p, f, f->protoctx) == 1)) {
713  f = TcpReuseReplace(tv, dtv, fb, f, hash, p);
714  if (f == NULL) {
715  FBLOCK_UNLOCK(fb);
716  return NULL;
717  }
718  }
719 
720  FlowReference(dest, f);
721 
722  FBLOCK_UNLOCK(fb);
723  return f;
724 }
725 
726 static inline int FlowCompareKey(Flow *f, FlowKey *key)
727 {
728  if ((f->proto != IPPROTO_TCP) && (f->proto != IPPROTO_UDP))
729  return 0;
730  return CmpFlowKey(f, key);
731 }
732 
733 /** \brief Get or create a Flow using a FlowKey
734  *
735  * Hash retrieval function for flows. Looks up the hash bucket containing the
736  * flow pointer. Then compares the packet with the found flow to see if it is
737  * the flow we need. If it isn't, walk the list until the right flow is found.
738  * Return a new Flow if ever no Flow was found.
739  *
740  *
741  * \param key Pointer to FlowKey build using flow to look for
742  * \param ttime time to use for flow creation
743  * \param hash Value of the flow hash
744  * \retval f *LOCKED* flow or NULL
745  */
746 
747 Flow *FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
748 {
749  Flow *f = FlowGetExistingFlowFromHash(key, hash);
750 
751  if (f != NULL) {
752  return f;
753  }
754 
755  /* No existing flow so let's get one new */
757  if (f == NULL) {
758  /* now see if we can alloc a new flow */
759  f = FlowAlloc();
760  if (f == NULL) {
761  SCLogDebug("Can't get a spare flow at start");
762  return NULL;
763  }
764  }
765  f->proto = key->proto;
766  f->vlan_id[0] = key->vlan_id[0];
767  f->vlan_id[1] = key->vlan_id[1];
768  f->src.addr_data32[0] = key->src.addr_data32[0];
769  f->src.addr_data32[1] = key->src.addr_data32[1];
770  f->src.addr_data32[2] = key->src.addr_data32[2];
771  f->src.addr_data32[3] = key->src.addr_data32[3];
772  f->dst.addr_data32[0] = key->dst.addr_data32[0];
773  f->dst.addr_data32[1] = key->dst.addr_data32[1];
774  f->dst.addr_data32[2] = key->dst.addr_data32[2];
775  f->dst.addr_data32[3] = key->dst.addr_data32[3];
776  f->sp = key->sp;
777  f->dp = key->dp;
778  f->recursion_level = 0;
779  f->flow_hash = hash;
780  if (key->src.family == AF_INET) {
781  f->flags |= FLOW_IPV4;
782  } else if (key->src.family == AF_INET6) {
783  f->flags |= FLOW_IPV6;
784  }
785 
787  /* set timestamp to now */
788  f->startts.tv_sec = ttime->tv_sec;
789  f->startts.tv_usec = ttime->tv_nsec * 1000;
790  f->lastts = f->startts;
791 
792  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
793  FBLOCK_LOCK(fb);
794  f->fb = fb;
795  if (fb->head == NULL) {
796  fb->head = f;
797  fb->tail = f;
798  } else {
799  f->hprev = fb->tail;
800  f->hprev->hnext = f;
801  fb->tail = f;
802  }
803  FLOWLOCK_WRLOCK(f);
804  FBLOCK_UNLOCK(fb);
805 
806  return f;
807 }
808 
809 /** \brief Look for existing Flow using a FlowKey
810  *
811  * Hash retrieval function for flows. Looks up the hash bucket containing the
812  * flow pointer. Then compares the packet with the found flow to see if it is
813  * the flow we need. If it isn't, walk the list until the right flow is found.
814  *
815  *
816  * \param key Pointer to FlowKey build using flow to look for
817  * \param hash Value of the flow hash
818  * \retval f *LOCKED* flow or NULL
819  */
820 Flow *FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash)
821 {
822  /* get our hash bucket and lock it */
823  FlowBucket *fb = &flow_hash[hash % flow_config.hash_size];
824  FBLOCK_LOCK(fb);
825 
826  SCLogDebug("fb %p fb->head %p", fb, fb->head);
827 
828  /* return if the bucket don't have a flow */
829  if (fb->head == NULL) {
830  FBLOCK_UNLOCK(fb);
831  return NULL;
832  }
833 
834  /* ok, we have a flow in the bucket. Let's find out if it is our flow */
835  Flow *f = fb->head;
836 
837  /* see if this is the flow we are looking for */
838  if (FlowCompareKey(f, key) == 0) {
839  while (f) {
840  f = f->hnext;
841 
842  if (f == NULL) {
843  FBLOCK_UNLOCK(fb);
844  return NULL;
845  }
846 
847  if (FlowCompareKey(f, key) != 0) {
848  /* found our flow, lock & return */
849  FLOWLOCK_WRLOCK(f);
850 
851  FBLOCK_UNLOCK(fb);
852  return f;
853  }
854  }
855  }
856 
857  /* lock & return */
858  FLOWLOCK_WRLOCK(f);
859 
860  FBLOCK_UNLOCK(fb);
861  return f;
862 }
863 
864 /** \internal
865  * \brief Get a flow from the hash directly.
866  *
867  * Called in conditions where the spare queue is empty and memcap is reached.
868  *
869  * Walks the hash until a flow can be freed. Timeouts are disregarded, use_cnt
870  * is adhered to. "flow_prune_idx" atomic int makes sure we don't start at the
871  * top each time since that would clear the top of the hash leading to longer
872  * and longer search times under high pressure (observed).
873  *
874  * \param tv thread vars
875  * \param dtv decode thread vars (for flow log api thread data)
876  *
877  * \retval f flow or NULL
878  */
879 static Flow *FlowGetUsedFlow(ThreadVars *tv, DecodeThreadVars *dtv)
880 {
881  uint32_t idx = SC_ATOMIC_GET(flow_prune_idx) % flow_config.hash_size;
882  uint32_t cnt = flow_config.hash_size;
883  uint32_t tried = 0;
884 
885  while (cnt--) {
886  tried++;
887  if (++idx >= flow_config.hash_size)
888  idx = 0;
889 
890  if (tried >= 25) {
891  (void) SC_ATOMIC_ADD(flow_prune_idx, (flow_config.hash_size - cnt));
892  break;
893  }
894 
895  FlowBucket *fb = &flow_hash[idx];
896 
897  if (FBLOCK_TRYLOCK(fb) != 0)
898  continue;
899 
900  Flow *f = fb->tail;
901  if (f == NULL) {
902  FBLOCK_UNLOCK(fb);
903  continue;
904  }
905 
906  if (FLOWLOCK_TRYWRLOCK(f) != 0) {
907  FBLOCK_UNLOCK(fb);
908  continue;
909  }
910 
911  /** never prune a flow that is used by a packet or stream msg
912  * we are currently processing in one of the threads */
913  if (SC_ATOMIC_GET(f->use_cnt) > 0) {
914  FBLOCK_UNLOCK(fb);
915  FLOWLOCK_UNLOCK(f);
916  continue;
917  }
918 
919  /* remove from the hash */
920  if (f->hprev != NULL)
921  f->hprev->hnext = f->hnext;
922  if (f->hnext != NULL)
923  f->hnext->hprev = f->hprev;
924  if (fb->head == f)
925  fb->head = f->hnext;
926  if (fb->tail == f)
927  fb->tail = f->hprev;
928 
929  f->hnext = NULL;
930  f->hprev = NULL;
931  f->fb = NULL;
932  SC_ATOMIC_SET(fb->next_ts, 0);
933  FBLOCK_UNLOCK(fb);
934 
935  int state = SC_ATOMIC_GET(f->flow_state);
936  if (state == FLOW_STATE_NEW)
938  else if (state == FLOW_STATE_ESTABLISHED)
940  else if (state == FLOW_STATE_CLOSED)
942 #ifdef CAPTURE_OFFLOAD
943  else if (state == FLOW_STATE_CAPTURE_BYPASSED)
945 #endif
946  else if (state == FLOW_STATE_LOCAL_BYPASSED)
948 
950 
951  if (SC_ATOMIC_GET(flow_flags) & FLOW_EMERGENCY)
953 
954  /* invoke flow log api */
957 
958  FlowClearMemory(f, f->protomap);
959 
961 
962  FLOWLOCK_UNLOCK(f);
963 
964  (void) SC_ATOMIC_ADD(flow_prune_idx, (flow_config.hash_size - cnt));
965  return f;
966  }
967 
968  return NULL;
969 }
FlowHashKey4_::ports
uint16_t ports[2]
Definition: flow-hash.c:86
FlowHashKey6_::recur
uint16_t recur
Definition: flow-hash.c:101
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:433
DecodeThreadVars_::counter_flow_udp
uint16_t counter_flow_udp
Definition: decode.h:675
ICMPV4_GET_EMB_PROTO
#define ICMPV4_GET_EMB_PROTO(p)
Definition: decode-icmpv4.h:232
Flow_::recursion_level
uint8_t recursion_level
Definition: flow.h:362
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:484
flow-util.h
FBLOCK_LOCK
#define FBLOCK_LOCK(fb)
Definition: flow-hash.h:68
DecodeThreadVars_::counter_flow_icmp4
uint16_t counter_flow_icmp4
Definition: decode.h:676
Flow_::startts
struct timeval startts
Definition: flow.h:474
Packet_::vlan_id
uint16_t vlan_id[2]
Definition: decode.h:438
FlowHashKey6_::proto
uint16_t proto
Definition: flow-hash.c:100
FlowKey_::src
Address src
Definition: flow.h:298
FLOW_END_FLAG_STATE_NEW
#define FLOW_END_FLAG_STATE_NEW
Definition: flow.h:226
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:355
FlowCnf_::hash_size
uint32_t hash_size
Definition: flow.h:281
FlowAddress_::address_un_data32
uint32_t address_un_data32[4]
Definition: flow.h:307
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
Flow_::hnext
struct Flow_ * hnext
Definition: flow.h:467
Flow_::proto
uint8_t proto
Definition: flow.h:361
Packet_::flags
uint32_t flags
Definition: decode.h:446
FlowKeyGetHash
uint32_t FlowKeyGetHash(FlowKey *fk)
Definition: flow-hash.c:224
threads.h
ICMPV4_DEST_UNREACH_IS_VALID
#define ICMPV4_DEST_UNREACH_IS_VALID(p)
Definition: decode-icmpv4.h:247
flow-private.h
Flow_
Flow data structure.
Definition: flow.h:343
Flow_::icmp_s
struct Flow_::@119::@123 icmp_s
Flow_::icmp_d
struct Flow_::@121::@124 icmp_d
Flow_::protomap
uint8_t protomap
Definition: flow.h:420
SC_ATOMIC_ADD
#define SC_ATOMIC_ADD(name, val)
add a value to our atomic variable
Definition: util-atomic.h:304
FLOWLOCK_TRYWRLOCK
#define FLOWLOCK_TRYWRLOCK(fb)
Definition: flow.h:259
PKT_WANTS_FLOW
#define PKT_WANTS_FLOW
Definition: decode.h:1108
flow-hash.h
FlowHashKey6_::u32
const uint32_t u32[11]
Definition: flow-hash.c:104
FLOW_END_FLAG_STATE_ESTABLISHED
#define FLOW_END_FLAG_STATE_ESTABLISHED
Definition: flow.h:227
FlowHashKey4_::u32
const uint32_t u32[5]
Definition: flow-hash.c:91
Flow_::vlan_id
uint16_t vlan_id[2]
Definition: flow.h:363
FLOW_END_FLAG_STATE_BYPASSED
#define FLOW_END_FLAG_STATE_BYPASSED
Definition: flow.h:233
FlowHashKey4_::vlan_id
uint16_t vlan_id[2]
Definition: flow-hash.c:89
FlowHashKey4
struct FlowHashKey4_ FlowHashKey4
FBLOCK_TRYLOCK
#define FBLOCK_TRYLOCK(fb)
Definition: flow-hash.h:69
DecodeThreadVars_::counter_flow_tcp
uint16_t counter_flow_tcp
Definition: decode.h:674
Address_::address_un_data32
uint32_t address_un_data32[4]
Definition: decode.h:116
proto
uint8_t proto
Definition: decode-template.h:0
Flow_::dp
Port dp
Definition: flow.h:355
Flow_::protoctx
void * protoctx
Definition: flow.h:416
FLOW_IPV4
#define FLOW_IPV4
Definition: flow.h:94
FLOWLOCK_UNLOCK
#define FLOWLOCK_UNLOCK(fb)
Definition: flow.h:260
flow_spare_q
FlowQueue flow_spare_q
Definition: flow.c:95
Packet_::icmp_d
struct Packet_::@42::@50 icmp_d
FLOW_CHECK_MEMCAP
#define FLOW_CHECK_MEMCAP(size)
check if a memory alloc would fit in the memcap
Definition: flow-util.h:135
Flow_::dst
FlowAddress dst
Definition: flow.h:346
Flow_::fb
struct FlowBucket_ * fb
Definition: flow.h:469
FlowHashKey6_::ports
uint16_t ports[2]
Definition: flow-hash.c:99
FLOW_STATE_LOCAL_BYPASSED
@ FLOW_STATE_LOCAL_BYPASSED
Definition: flow.h:486
decode.h
util-debug.h
ICMPV4_GET_EMB_IPV4
#define ICMPV4_GET_EMB_IPV4(p)
Definition: decode-icmpv4.h:234
FlowAddress_::address
union FlowAddress_::@118 address
FLOWLOCK_WRLOCK
#define FLOWLOCK_WRLOCK(fb)
Definition: flow.h:257
SC_ATOMIC_EXTERN
SC_ATOMIC_EXTERN(unsigned int, flow_prune_idx)
FlowKey_::recursion_level
uint8_t recursion_level
Definition: flow.h:301
ICMPV4Vars_::emb_dport
uint16_t emb_dport
Definition: decode-icmpv4.h:203
ThreadVars_
Per thread variable structure.
Definition: threadvars.h:58
Flow_::flow_end_flags
uint8_t flow_end_flags
Definition: flow.h:422
FlowStorageSize
unsigned int FlowStorageSize(void)
Definition: flow-storage.c:34
Packet_::sp
Port sp
Definition: decode.h:418
FlowHashKey6
struct FlowHashKey6_ FlowHashKey6
util-time.h
app-layer-parser.h
FlowGetExistingFlowFromHash
Flow * FlowGetExistingFlowFromHash(FlowKey *key, const uint32_t hash)
Look for existing Flow using a FlowKey.
Definition: flow-hash.c:820
FlowThreadId
uint16_t FlowThreadId
Definition: flow.h:322
FlowKey_::sp
Port sp
Definition: flow.h:299
FlowTimeoutsEmergency
void FlowTimeoutsEmergency(void)
Definition: flow-manager.c:103
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:411
conf.h
Packet_::ip4h
IPV4Hdr * ip4h
Definition: decode.h:503
Port
uint16_t Port
Definition: decode.h:238
FLOW_END_FLAG_EMERGENCY
#define FLOW_END_FLAG_EMERGENCY
Definition: flow.h:229
FBLOCK_UNLOCK
#define FBLOCK_UNLOCK(fb)
Definition: flow-hash.h:70
FlowKey_::vlan_id
uint16_t vlan_id[2]
Definition: flow.h:302
FlowHashKey4_
Definition: flow-hash.c:82
FlowClearMemory
int FlowClearMemory(Flow *f, uint8_t proto_map)
Function clear the flow memory before queueing it to spare flow queue.
Definition: flow.c:1035
FlowGetFlowFromHash
Flow * FlowGetFlowFromHash(ThreadVars *tv, DecodeThreadVars *dtv, const Packet *p, Flow **dest)
Get Flow for packet.
Definition: flow-hash.c:604
FlowCnf_::hash_rand
uint32_t hash_rand
Definition: flow.h:280
FlowHashKey4_::addrs
uint32_t addrs[2]
Definition: flow-hash.c:85
output-flow.h
FlowWakeupFlowManagerThread
#define FlowWakeupFlowManagerThread()
Definition: flow-manager.h:34
detect-engine-state.h
Data structures and function prototypes for keeping state for the detection engine.
FlowHashKey6_
Definition: flow-hash.c:95
Flow_::flow_hash
uint32_t flow_hash
Definition: flow.h:370
Flow_::src
FlowAddress src
Definition: flow.h:346
dtv
DecodeThreadVars * dtv
Definition: fuzz_decodepcapfile.c:30
Flow_::lastts
struct timeval lastts
Definition: flow.h:375
Packet_::icmp_s
struct Packet_::@40::@49 icmp_s
FlowHashKey6_::src
uint32_t src[4]
Definition: flow-hash.c:98
flow_hash
FlowBucket * flow_hash
Definition: flow-hash.c:52
FlowBucket_::head
Flow * head
Definition: flow-hash.h:42
FlowDequeue
Flow * FlowDequeue(FlowQueue *q)
remove a flow from the queue
Definition: flow-queue.c:105
Packet_::icmpv4vars
ICMPV4Vars icmpv4vars
Definition: decode.h:518
flow-storage.h
FLOW_STATE_NEW
@ FLOW_STATE_NEW
Definition: flow.h:483
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:96
DecodeThreadVars_::counter_flow_icmp6
uint16_t counter_flow_icmp6
Definition: decode.h:677
Packet_::tcph
TCPHdr * tcph
Definition: decode.h:525
flow_config
FlowConfig flow_config
Definition: flow.c:97
FlowKey_::dst
Address dst
Definition: flow.h:298
FlowHashKey4_::recur
uint16_t recur
Definition: flow-hash.c:88
FLOW_END_FLAG_STATE_CLOSED
#define FLOW_END_FLAG_STATE_CLOSED
Definition: flow.h:228
util-hash-lookup3.h
tv
ThreadVars * tv
Definition: fuzz_decodepcapfile.c:29
PKT_IS_ICMPV4
#define PKT_IS_ICMPV4(p)
Definition: decode.h:258
FlowHashKey6_::dst
uint32_t dst[4]
Definition: flow-hash.c:98
ICMPV4_IS_ERROR_MSG
#define ICMPV4_IS_ERROR_MSG(p)
Definition: decode-icmpv4.h:264
g_vlan_mask
uint16_t g_vlan_mask
Definition: suricata.c:233
Packet_::flow_hash
uint32_t flow_hash
Definition: decode.h:452
FLOW_TCP_REUSED
#define FLOW_TCP_REUSED
Definition: flow.h:51
FlowKey_::proto
uint8_t proto
Definition: flow.h:300
FLOW_STATE_CLOSED
@ FLOW_STATE_CLOSED
Definition: flow.h:485
FlowHashKey4_::proto
uint16_t proto
Definition: flow-hash.c:87
DecodeThreadVars_
Structure to hold thread specific data for all decode modules.
Definition: decode.h:625
FlowGetFromFlowKey
Flow * FlowGetFromFlowKey(FlowKey *key, struct timespec *ttime, const uint32_t hash)
Get or create a Flow using a FlowKey.
Definition: flow-hash.c:747
Flow_::flags
uint32_t flags
Definition: flow.h:396
Packet_::recursion_level
uint8_t recursion_level
Definition: decode.h:436
DecodeThreadVars_::output_flow_thread_data
void * output_flow_thread_data
Definition: decode.h:683
FlowKey_
Definition: flow.h:297
Packet_::udph
UDPHdr * udph
Definition: decode.h:527
FLOW_EMERGENCY
#define FLOW_EMERGENCY
Definition: flow-private.h:37
FlowHashKey6_::vlan_id
uint16_t vlan_id[2]
Definition: flow-hash.c:102
Address_::address
union Address_::@39 address
Address_::family
char family
Definition: decode.h:114
Packet_::dst
Address dst
Definition: decode.h:416
DecodeThreadVars_::counter_flow_memcap
uint16_t counter_flow_memcap
Definition: decode.h:672
Flow_::hprev
struct Flow_ * hprev
Definition: flow.h:468
Flow_::sp
Port sp
Definition: flow.h:348
ICMPV4Vars_::emb_sport
uint16_t emb_sport
Definition: decode-icmpv4.h:202
Packet_::ip6h
IPV6Hdr * ip6h
Definition: decode.h:505
SC_ATOMIC_GET
#define SC_ATOMIC_GET(name)
Get the value from the atomic variable.
Definition: util-atomic.h:347
flow.h
FlowAlloc
Flow * FlowAlloc(void)
allocate a flow
Definition: flow-util.c:51
Packet_::dp
Port dp
Definition: decode.h:426
FLOW_END_FLAG_FORCED
#define FLOW_END_FLAG_FORCED
Definition: flow.h:231
FlowKey_::dp
Port dp
Definition: flow.h:299
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:408
Packet_::src
Address src
Definition: decode.h:415
FlowUpdateState
void FlowUpdateState(Flow *f, enum FlowState s)
Definition: flow.c:1113
output.h
TcpSessionPacketSsnReuse
int TcpSessionPacketSsnReuse(const Packet *p, const Flow *f, void *tcp_ssn)
Flow_::thread_id
FlowThreadId thread_id[2]
Definition: flow.h:442
SC_ATOMIC_OR
#define SC_ATOMIC_OR(name, val)
Bitwise OR a value to our atomic variable.
Definition: util-atomic.h:322