From e3b76dcaad9dad492bf344aac89fa4f8e0cf76d8 Mon Sep 17 00:00:00 2001 From: Gurvinder Singh Date: Sun, 30 Aug 2009 00:40:31 +0300 Subject: [PATCH] efficient protocol specific timeouts --- src/flow-private.h | 16 +-- src/flow-util.c | 2 - src/flow.c | 262 ++++++++++++++++----------------------------- src/flow.h | 18 ++-- 4 files changed, 109 insertions(+), 189 deletions(-) diff --git a/src/flow-private.h b/src/flow-private.h index afd891584a..56d3a398b3 100644 --- a/src/flow-private.h +++ b/src/flow-private.h @@ -18,14 +18,14 @@ #define FLOW_EMERGENCY 0x01 /* Flow Time out values */ -/*#define FLOW_DEFAULT_NEW_TIMEOUT 30 +#define FLOW_DEFAULT_NEW_TIMEOUT 30 #define FLOW_DEFAULT_EST_TIMEOUT 300 -#define FLOW_IPPROTO_TCP_NEW_TIMEOUT 40 -#define FLOW_IPPROTO_TCP_EST_TIMEOUT 400 -#define FLOW_IPPROTO_UDP_NEW_TIMEOUT 20 -#define FLOW_IPPROTO_UDP_EST_TIMEOUT 200 -#define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 25 -#define FLOW_IPPROTO_ICMP_EST_TIMEOUT 250 +#define FLOW_IPPROTO_TCP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_TCP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_UDP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_UDP_EST_TIMEOUT 300 +#define FLOW_IPPROTO_ICMP_NEW_TIMEOUT 30 +#define FLOW_IPPROTO_ICMP_EST_TIMEOUT 300 #define FLOW_DEFAULT_EMERG_NEW_TIMEOUT 10 #define FLOW_DEFAULT_EMERG_EST_TIMEOUT 100 @@ -34,7 +34,7 @@ #define FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT 10 #define FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT 100 #define FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT 10 -#define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100*/ +#define FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT 100 /* * Variables diff --git a/src/flow-util.c b/src/flow-util.c index e117ff3f11..642d908f23 100644 --- a/src/flow-util.c +++ b/src/flow-util.c @@ -81,8 +81,6 @@ void FlowInit(Flow *f, Packet *p) printf("FIXME: %s:%s:%" PRId32 "\n", __FILE__, __FUNCTION__, __LINE__); } - FlowSetInitTimeouts(f); - COPY_TIMESTAMP(&p->ts, &f->startts); } diff --git a/src/flow.c b/src/flow.c index 50c3e4e2d9..8bee2a7716 100644 --- a/src/flow.c +++ b/src/flow.c @@ -33,32 +33,14 @@ #define FLOW_DEFAULT_PREALLOC 10000 -/*Protocols specific timeouts. As we need to redefine their values too !!*/ -/*TCP*/ -uint32_t tcp_new_timeout = 30; -uint32_t tcp_est_timeout = 300; -uint32_t tcp_emerg_new_timeout = 10; -uint32_t tcp_emerg_est_timeout= 100; -/*UDP*/ -uint32_t udp_new_timeout = 30; -uint32_t udp_est_timeout = 300; -uint32_t udp_emerg_new_timeout = 10; -uint32_t udp_emerg_est_timeout= 100; -/*ICMP*/ -uint32_t icmp_new_timeout = 30; -uint32_t icmp_est_timeout = 300; -uint32_t icmp_emerg_new_timeout = 10; -uint32_t icmp_emerg_est_timeout= 100; -/*DEFAULT*/ -uint32_t default_new_timeout = 30; -uint32_t default_est_timeout = 300; -uint32_t default_emerg_new_timeout = 10; -uint32_t default_emerg_est_timeout= 100; +/*Protocols specific timeouts*/ +uint32_t proto_timeouts[255][4]; void FlowRegisterTests (void); static void FlowClearProtocolMemory (Flow *); -void FlowSetInitTimeouts(Flow *); -static int FlowSetProtoTimout(uint8_t, uint8_t, uint32_t , uint32_t ); +void FlowInitProtoTimeouts(); +static int FlowUpdateSpareFlows(void); +int FlowSetProtoTimout(uint8_t ,uint8_t, uint32_t ,uint32_t ); /** \brief Update the flows position in the queue's * \param f Flow to requeue. * @@ -99,7 +81,7 @@ static void FlowUpdateQueue(Flow *f) * \retval 0 on error, failed block, nothing to prune * \retval 1 on successfully pruned one */ -static int FlowPrune (FlowQueue *q, struct timeval *ts, uint8_t emerg, uint8_t flow_type) +static int FlowPrune (FlowQueue *q, struct timeval *ts) { if (mutex_trylock(&q->mutex_q) != 0) { return 0; @@ -124,30 +106,36 @@ static int FlowPrune (FlowQueue *q, struct timeval *ts, uint8_t emerg, uint8_t f } uint32_t timeout = 0; - if (emerg == TRUE) { - switch (flow_type) { - case FLOW_NEW: - timeout = f->emerg_new_timeout; - break; - case FLOW_ESTABLISHED: - timeout = f->emerg_est_timeout; - break; - default: - break; - } + if (!(FlowUpdateSpareFlows()) && (flow_flags & FLOW_EMERGENCY)) { + if (f->flags & FLOW_EST_LIST) + timeout = proto_timeouts[f->proto][EMERG_ESTABLISHED]; + else + timeout = proto_timeouts[f->proto][EMERG_NEW]; } else { - switch (flow_type) { - case FLOW_NEW: - timeout = f->new_timeout; - break; - case FLOW_ESTABLISHED: - timeout = f->est_timeout; - break; - default: - break; - } + if (f->flags & FLOW_EST_LIST) + timeout = proto_timeouts[f->proto][ESTABLISHED]; + else + timeout = proto_timeouts[f->proto][NEW]; } + /*XXX GS Default Case (unsupported protocols), we have avoided this check + and set all the array except supported protocols with default timeouts + values during initialization.it will increase performance during run time + (your thoughts)?? + if (timeout == 0) { + if (!(FlowUpdateSpareFlows()) && (flow_flags & FLOW_EMERGENCY)) { + if (f->flags & FLOW_EST_LIST) + timeout = proto_timeouts[0][EMERG_ESTABLISHED]; + else + timeout = proto_timeouts[0][EMERG_NEW]; + } else { + if (f->flags & FLOW_EST_LIST) + timeout = proto_timeouts[0][ESTABLISHED]; + else + timeout = proto_timeouts[0][NEW]; + } + }*/ + DEBUGPRINT("got lock, now check: %" PRId64 "+%" PRIu32 "=(%" PRId64 ") < %" PRId64 "", f->lastts.tv_sec, timeout, f->lastts.tv_sec + timeout, ts->tv_sec); @@ -195,10 +183,10 @@ static int FlowPrune (FlowQueue *q, struct timeval *ts, uint8_t emerg, uint8_t f * \param timeout timeout to consider * \retval cnt number of flows that are timed out */ -static uint32_t FlowPruneFlows(FlowQueue *q, struct timeval *ts, uint8_t emerg, uint8_t flow_type) +static uint32_t FlowPruneFlows(FlowQueue *q, struct timeval *ts) { uint32_t cnt = 0; - while(FlowPrune(q, ts, emerg, flow_type)) { cnt++; } + while(FlowPrune(q, ts)) { cnt++; } return cnt; } @@ -343,10 +331,10 @@ void FlowInitConfig (char quiet) flow_config.memcap = FLOW_DEFAULT_MEMCAP; flow_config.prealloc = FLOW_DEFAULT_PREALLOC; /* init timeouts */ - flow_config.timeout_new = default_new_timeout; - flow_config.timeout_est = default_est_timeout; - flow_config.emerg_timeout_new = default_emerg_new_timeout; - flow_config.emerg_timeout_est = default_emerg_est_timeout; + flow_config.timeout_new = FLOW_DEFAULT_NEW_TIMEOUT; + flow_config.timeout_est = FLOW_DEFAULT_EST_TIMEOUT; + flow_config.emerg_timeout_new = FLOW_DEFAULT_EMERG_NEW_TIMEOUT; + flow_config.emerg_timeout_est = FLOW_DEFAULT_EMERG_EST_TIMEOUT; /* alloc hash memory */ flow_hash = calloc(flow_config.hash_size, sizeof(FlowBucket)); @@ -379,6 +367,7 @@ void FlowInitConfig (char quiet) flow_config.memuse, flow_config.memcap); } + FlowInitProtoTimeouts(); } @@ -447,8 +436,6 @@ void *FlowManagerThread(void *td) uint32_t established_cnt = 0, new_cnt = 0, nowcnt; uint32_t sleeping = 0; uint8_t emerg = FALSE; - uint8_t flow_type; - uint8_t emerg_timeout = FALSE; printf("%s started...\n", th_v->name); @@ -471,24 +458,21 @@ void *FlowManagerThread(void *td) TimeGet(&ts); DEBUGPRINT("ts %" PRId64 "", ts.tv_sec); - /* see if we still have enough spare flows */ + /* see if we still have enough spare flows if (!(FlowUpdateSpareFlows()) && emerg == TRUE) { - emerg_timeout = TRUE; - /*timeout_new = flow_config.emerg_timeout_new; - timeout_est = flow_config.emerg_timeout_est;*/ - } + timeout_new = flow_config.emerg_timeout_new; + timeout_est = flow_config.emerg_timeout_est; + }*/ /* prune new list */ - flow_type = FLOW_NEW; - nowcnt = FlowPruneFlows(&flow_new_q, &ts, emerg_timeout, flow_type); + nowcnt = FlowPruneFlows(&flow_new_q, &ts); if (nowcnt) { DEBUGPRINT("Pruned %" PRIu32 " new flows...\n", nowcnt); new_cnt += nowcnt; } /* prune established list */ - flow_type = FLOW_ESTABLISHED; - nowcnt = FlowPruneFlows(&flow_est_q, &ts, emerg_timeout, flow_type); + nowcnt = FlowPruneFlows(&flow_est_q, &ts); if (nowcnt) { DEBUGPRINT("Pruned %" PRIu32 " established flows...\n", nowcnt); established_cnt += nowcnt; @@ -536,33 +520,36 @@ void FlowManagerThreadSpawn() return; } -void FlowSetInitTimeouts (Flow *f) { - switch (f->proto) { - case IPPROTO_TCP: - f->new_timeout = tcp_new_timeout; - f->est_timeout = tcp_est_timeout; - f->emerg_new_timeout = tcp_emerg_new_timeout; - f->emerg_est_timeout = tcp_emerg_est_timeout; - break; - case IPPROTO_UDP: - f->new_timeout = udp_new_timeout; - f->est_timeout = udp_est_timeout; - f->emerg_new_timeout = udp_emerg_new_timeout; - f->emerg_est_timeout = udp_emerg_est_timeout; - break; - case IPPROTO_ICMP: - f->new_timeout = icmp_new_timeout; - f->est_timeout = icmp_est_timeout; - f->emerg_new_timeout = icmp_emerg_new_timeout; - f->emerg_est_timeout = icmp_emerg_est_timeout; - break; - default: - f->new_timeout = default_new_timeout; - f->est_timeout = default_est_timeout; - f->emerg_new_timeout = default_emerg_new_timeout; - f->emerg_est_timeout = default_emerg_est_timeout; - break; +void FlowInitProtoTimeouts (void) { + + uint8_t i; + /*Setting up default value for all protocols. it will improve performance + while lookup timeouts for unsupported protocols. Initialization cost is less + expensive compared to cost at run time!!*/ + for (i=0; i<255; i++) { + proto_timeouts[i][NEW] = FLOW_DEFAULT_NEW_TIMEOUT; + proto_timeouts[i][ESTABLISHED] = FLOW_DEFAULT_EST_TIMEOUT; + proto_timeouts[i][EMERG_NEW] = FLOW_DEFAULT_EMERG_NEW_TIMEOUT; + proto_timeouts[i][EMERG_ESTABLISHED] = FLOW_DEFAULT_EMERG_EST_TIMEOUT; } + /*Checking i == IPPROTO_... 255 times is more expensive then reinitialsing + supported IPPROTO timeouts values !!*/ + /*TCP*/ + proto_timeouts[IPPROTO_TCP][NEW] = FLOW_IPPROTO_TCP_NEW_TIMEOUT; + proto_timeouts[IPPROTO_TCP][ESTABLISHED] = FLOW_IPPROTO_TCP_EST_TIMEOUT; + proto_timeouts[IPPROTO_TCP][EMERG_NEW] = FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT; + proto_timeouts[IPPROTO_TCP][EMERG_ESTABLISHED] = FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT; + /*UDP*/ + proto_timeouts[IPPROTO_UDP][NEW] = FLOW_IPPROTO_UDP_NEW_TIMEOUT; + proto_timeouts[IPPROTO_UDP][ESTABLISHED] = FLOW_IPPROTO_UDP_EST_TIMEOUT; + proto_timeouts[IPPROTO_UDP][EMERG_NEW] = FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT; + proto_timeouts[IPPROTO_UDP][EMERG_ESTABLISHED] = FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT; + /*ICMP*/ + proto_timeouts[IPPROTO_ICMP][NEW] = FLOW_IPPROTO_ICMP_NEW_TIMEOUT; + proto_timeouts[IPPROTO_ICMP][ESTABLISHED] = FLOW_IPPROTO_ICMP_EST_TIMEOUT; + proto_timeouts[IPPROTO_ICMP][EMERG_NEW] = FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT; + proto_timeouts[IPPROTO_ICMP][EMERG_ESTABLISHED] = FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT; + } static void FlowClearProtocolMemory (Flow *f) { @@ -572,10 +559,6 @@ static void FlowClearProtocolMemory (Flow *f) { memset(&add, 0, sizeof(Address)); f->dp = 0; f->sp = 0; - f->emerg_est_timeout = 0; - f->emerg_new_timeout = 0; - f->est_timeout = 0; - f->new_timeout = 0; f->proto = 0; f->recursion_level = 0; f->bytecnt = 0; @@ -585,102 +568,43 @@ static void FlowClearProtocolMemory (Flow *f) { f->dst = add; } -static int FlowSetProtoTimout(uint8_t proto, uint8_t emerg_timeout, uint32_t new_timeout, uint32_t est_timeout) { - switch (proto) { - case IPPROTO_TCP: - if(emerg_timeout) { - tcp_emerg_new_timeout = new_timeout; - tcp_emerg_est_timeout = est_timeout; - } else { - tcp_new_timeout = new_timeout; - tcp_est_timeout = est_timeout; - } - break; - case IPPROTO_UDP: - if(emerg_timeout) { - udp_emerg_new_timeout = new_timeout; - udp_emerg_est_timeout = est_timeout; - } else { - udp_new_timeout = new_timeout; - udp_est_timeout = est_timeout; - } - break; - case IPPROTO_ICMP: - if(emerg_timeout) { - icmp_emerg_new_timeout = new_timeout; - icmp_emerg_est_timeout = est_timeout; - } else { - icmp_new_timeout = new_timeout; - icmp_est_timeout = est_timeout; - } - break; - default: - if(emerg_timeout) { - default_emerg_new_timeout = new_timeout; - default_emerg_est_timeout = est_timeout; - } else { - default_new_timeout = new_timeout; - default_est_timeout = est_timeout; - } - break; +int FlowSetProtoTimout(uint8_t proto, uint8_t emerg, uint32_t new_timeout, uint32_t est_timeout) { + + if (emerg) { + proto_timeouts[proto][EMERG_NEW] = new_timeout; + proto_timeouts[proto][EMERG_ESTABLISHED] = est_timeout; + } else { + proto_timeouts[proto][NEW] = new_timeout; + proto_timeouts[proto][ESTABLISHED] = est_timeout; } + + return 1; } static int FlowTest01 (void) { - ThreadVars tv; - Packet p; - struct in_addr in; - IPV4Hdr iphdr; - TCPHdr tcph; - - memset(&tv, 0, sizeof(ThreadVars)); - memset(&p, 0, sizeof(Packet)); - memset(&iphdr, 0, sizeof(IPV4Hdr)); - memset(&tcph, 0, sizeof(TCPHdr)); - - inet_pton(AF_INET, "1.2.3.4", &in); - iphdr.ip_src = in; - iphdr.ip_dst = in; - iphdr.ip_proto = IPPROTO_TCP; - tcph.th_dport = ntohs(20); - tcph.th_sport = ntohs(24); - - p.tcph = &tcph; - p.ip4h = &iphdr; - p.proto = IPPROTO_TCP; FlowInitConfig(TRUE); - FlowHandlePacket(&tv, &p); - if ((p.flow->new_timeout != tcp_new_timeout) && (p.flow->est_timeout != tcp_est_timeout) - && (p.flow->emerg_new_timeout != tcp_emerg_new_timeout) && (p.flow->emerg_est_timeout != tcp_emerg_est_timeout)){ + if ((proto_timeouts[IPPROTO_TCP][NEW] != FLOW_IPPROTO_TCP_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_TCP][ESTABLISHED] != FLOW_IPPROTO_TCP_EST_TIMEOUT) + && (proto_timeouts[IPPROTO_TCP][EMERG_NEW] != FLOW_IPPROTO_TCP_EMERG_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_TCP][EMERG_ESTABLISHED] != FLOW_IPPROTO_TCP_EMERG_EST_TIMEOUT)){ printf ("failed in setting TCP flow timeout"); return 0; } - p.proto = IPPROTO_UDP; - FlowHandlePacket(&tv, &p); - - if ((p.flow->new_timeout != udp_new_timeout) && (p.flow->est_timeout != udp_est_timeout) - && (p.flow->emerg_new_timeout != udp_emerg_new_timeout) && (p.flow->emerg_est_timeout != udp_emerg_est_timeout)){ + if ((proto_timeouts[IPPROTO_UDP][NEW] != FLOW_IPPROTO_UDP_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_UDP][ESTABLISHED] != FLOW_IPPROTO_UDP_EST_TIMEOUT) + && (proto_timeouts[IPPROTO_UDP][EMERG_NEW] != FLOW_IPPROTO_UDP_EMERG_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_UDP][EMERG_ESTABLISHED] != FLOW_IPPROTO_UDP_EMERG_EST_TIMEOUT)){ printf ("failed in setting UDP flow timeout"); return 0; } - p.proto = IPPROTO_ICMP; - FlowHandlePacket(&tv, &p); - - if ((p.flow->new_timeout != icmp_new_timeout) && (p.flow->est_timeout != icmp_est_timeout) - && (p.flow->emerg_new_timeout != icmp_emerg_new_timeout) && (p.flow->emerg_est_timeout != icmp_emerg_est_timeout)){ + if ((proto_timeouts[IPPROTO_ICMP][NEW] != FLOW_IPPROTO_ICMP_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_ICMP][ESTABLISHED] != FLOW_IPPROTO_ICMP_EST_TIMEOUT) + && (proto_timeouts[IPPROTO_ICMP][EMERG_NEW] != FLOW_IPPROTO_ICMP_EMERG_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_ICMP][EMERG_ESTABLISHED] != FLOW_IPPROTO_ICMP_EMERG_EST_TIMEOUT)){ printf ("failed in setting ICMP flow timeout"); return 0; } - p.proto = IPPROTO_DCCP; - FlowHandlePacket(&tv, &p); - - if ((p.flow->new_timeout != default_new_timeout) && (p.flow->est_timeout != default_est_timeout) - && (p.flow->emerg_new_timeout != default_emerg_new_timeout) && (p.flow->emerg_est_timeout != default_emerg_est_timeout)){ + if ((proto_timeouts[IPPROTO_DCCP][NEW] != FLOW_DEFAULT_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_DCCP][ESTABLISHED] != FLOW_DEFAULT_EST_TIMEOUT) + && (proto_timeouts[IPPROTO_DCCP][EMERG_NEW] != FLOW_DEFAULT_EMERG_NEW_TIMEOUT) && (proto_timeouts[IPPROTO_DCCP][EMERG_ESTABLISHED] != FLOW_DEFAULT_EMERG_EST_TIMEOUT)){ printf ("failed in setting default flow timeout"); return 0; } diff --git a/src/flow.h b/src/flow.h index 9d2bde6184..0b9d72d395 100644 --- a/src/flow.h +++ b/src/flow.h @@ -8,8 +8,6 @@ #define FLOW_QUIET TRUE #define FLOW_VERBOSE FALSE -#define FLOW_NEW 0 -#define FLOW_ESTABLISHED 1 /* pkt flow flags */ #define FLOW_PKT_TOSERVER 0x01 @@ -56,13 +54,6 @@ typedef struct Flow_ uint8_t proto; uint8_t recursion_level; - /*flow timeouts for protocol specific timeouts*/ - uint32_t new_timeout; - uint32_t est_timeout; - - uint32_t emerg_new_timeout; - uint32_t emerg_est_timeout; - uint8_t flags; /* ts of flow init and last update */ @@ -93,6 +84,13 @@ typedef struct Flow_ struct FlowBucket_ *fb; } Flow; +enum { + NEW = 0, + ESTABLISHED, + EMERG_NEW, + EMERG_ESTABLISHED, +}; + void FlowHandlePacket (ThreadVars *, Packet *); void FlowInitConfig (char); void FlowPrintQueueInfo (void); @@ -104,7 +102,7 @@ void *FlowManagerThread(void *td); void FlowManagerThreadSpawn(void); void FlowRegisterTests (void); -void FlowSetInitTimeouts (Flow *); +int FlowSetProtoTimout(uint8_t ,uint8_t, uint32_t ,uint32_t ); #endif /* __FLOW_H__ */