📄 flow_cache.c
字号:
/**************************************************************************** * * Copyright (C) 2003-2008 Sourcefire, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as * published by the Free Software Foundation. You may not use, modify or * distribute this program under any other version of the GNU General * Public License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ****************************************************************************/ /** * @file flow_cache.c * @author Chris Green <cmg@sourcefire.com> * @date Fri Jun 20 09:04:51 2003 * * @brief where flows are stored * * The FlowCache is a memory-capped storage area for the FLOW * datatype. It is inspired by spp_conversation, ipaudit, stream4 and * frag2. * * * Each FLOW is uniquely identified by the 5-tuple (ipproto,sip,dip,sport,dport) * * Currently we only support IPV4 but new protocols will only require * the addition of additional protocol specific hash tables. Ideally, * the API will stay the same and just do a switch on the key type to * support the various address families. * * This is meant to centralize the state management routines so that * it's easy to just worry about higher level protocols in other * modules. * * This is built on top of sfxhash currently and relies on it for * memory management. flow_hash.c contains the hashing keys * */#define FLOW_PERF_FIX#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdio.h>#include "flow_cache.h"#include "flow_callback.h"#include "flow_hash.h"#include "bitop_funcs.h"#include "sf_types.h"/* helper functions */static int flowcache_anrfree( void *key, void *data);static int flowcache_usrfree( void *key, void *data);/* minor optimization functions */static INLINE int flowcache_mru(FLOWCACHE *flowcachep, FLOW **flowpp);static INLINE int flowcache_lru(FLOWCACHE *flowcachep, FLOW **flowpp);/* statistics functions */static INLINE int FCS_find(FLOWCACHE *flowcachecp, FLOWKEY *keyp);static INLINE int FCS_revfind(FLOWCACHE *flowcachecp, FLOWKEY *keyp);static INLINE int FCS_new(FLOWCACHE *flowcachecp, FLOWKEY *keyp);static INLINE int FCS_find_success(FLOWCACHE *flowcachecp, FLOWKEY *keyp);static INLINE int FCS_find_fail(FLOWCACHE *flowcachecp, FLOWKEY *keyp);int flowcache_init(FLOWCACHE *flowcachep, unsigned int rows, int memcap, int datasize, FLOWHASHID hashid){ int ret; int real_datasize = 0; if(!flowcachep) { return FLOW_ENULL; } if(datasize < 0) { return FLOW_ENULL; } if(memcap <= (int)(datasize + sizeof(FLOW) + sizeof(SFXHASH_NODE))) { /* come on man, you gotta give me enough memory to store 1. */ return FLOW_EINVALID; } if(rows < 1) return FLOW_EINVALID; /* zero out the struct for all the additional data strctures */ memset(flowcachep, 0, sizeof(FLOWCACHE)); /* ** If we have a datasize, then we need to decrement by 1 because ** the FLOWDATA already has one byte. */ if(datasize) { real_datasize = datasize - 1; } /* ** datasize-1 because there is already 1 byte in the FLOWDATA ** structure. */ flowcachep->ipv4_table = sfxhash_new(rows, /* # of nodes in HT*/ sizeof(FLOWKEY), /* size of the key */ sizeof(FLOW) + real_datasize, /* data size */ memcap, /* max memory */ 1, /* auto recover nodes */ flowcache_anrfree, /* autorecovery function */ flowcache_usrfree, /* data free function*/ 1); /* recycle old nodes */ if(flowcachep->ipv4_table == NULL) { return FLOW_ENOMEM; } /* set our hash function to something that understands ipv4 flowkeys */ switch(hashid) { case HASH1: ret = sfxhash_set_keyops(flowcachep->ipv4_table, flowkey_hashfcn1, flowkeycmp_fcn); break; case HASH2: ret = sfxhash_set_keyops(flowcachep->ipv4_table, flowkey_hashfcn2, flowkeycmp_fcn); break; default: ret = FLOW_EINVALID; } /* if setting the hash function or setting the comparison function fails, abort */ if(ret != 0) { sfxhash_delete(flowcachep->ipv4_table); return FLOW_BADJUJU; } flowcachep->max_flowbits_bytes = (unsigned int)datasize; return FLOW_SUCCESS;}int flowcache_destroy(FLOWCACHE *flowcachep){ if(!flowcachep) { return FLOW_ENULL; } sfxhash_delete(flowcachep->ipv4_table); flowcachep->ipv4_table = NULL; return FLOW_SUCCESS;}unsigned flowcache_overhead_blocks(FLOWCACHE *fcp){ return sfxhash_overhead_blocks(fcp->ipv4_table);}int flowcache_releaseflow(FLOWCACHE *flowcachep, FLOW **flowpp){ FLOWKEY *key; FLOWKEY search_key; if(!flowcachep || !flowpp || !(*flowpp)) { return FLOW_ENULL; } /** @todo remove any associated data with the flow */ key = &(*flowpp)->key; flowkey_normalize(&search_key, key); if(sfxhash_remove(flowcachep->ipv4_table, &search_key) != 0) { return FLOW_NOTFOUND; } /* we've successfully removed the node from the table */ *flowpp = NULL; return FLOW_SUCCESS;}int init_flowdata(FLOWCACHE *fcp, FLOW *flowp){ if(!flowp || !fcp) return 1; if(boInitStaticBITOP(&(flowp->data.boFlowbits), fcp->max_flowbits_bytes, flowp->data.flowb)) { return 1; } return 0;}int flowcache_newflow(FLOWCACHE *flowcachep, FLOWKEY *keyp, FLOW **flowpp){ static int run_once = 1;#ifdef FLOW_PERF_FIX FLOW *newflow = NULL; SFXHASH_NODE *new_node = NULL;#else static FLOW zeroflow;#endif static FLOWKEY searchkey; int ret; if(!flowcachep || !keyp || !flowpp) { return FLOW_ENULL; } FCS_new(flowcachep, keyp); if(run_once) { /* all the time that we're running this, we're actually going to be filling in the key, and having zero'd out counters */ #ifndef FLOW_PERF_FIX memset(&zeroflow, 0, sizeof(FLOW));#endif memset(&searchkey, 0, sizeof(FLOWKEY)); run_once = 0; } flowkey_normalize(&searchkey, keyp); #ifdef FLOW_PERF_FIX /* This just eliminates a memcpy. */ /* Since we're using auto node recovery, we should get a node back * here that has a data pointer. */ /* flow_init resets the internal key & stats to zero. */ new_node = sfxhash_get_node(flowcachep->ipv4_table, &searchkey); if (new_node && new_node->data) { newflow = new_node->data; if(flow_init(newflow, keyp->protocol, keyp->init_address, keyp->init_port, keyp->resp_address, keyp->resp_port)) { return FLOW_ENULL; } ret = SFXHASH_OK; } else { ret = SFXHASH_NOMEM; }#else if(flow_init(&zeroflow, keyp->protocol, keyp->init_address, keyp->init_port, keyp->resp_address, keyp->resp_port)) { return FLOW_ENULL; } ret = sfxhash_add(flowcachep->ipv4_table, &searchkey, &zeroflow);#endif switch(ret) { case SFXHASH_OK: if(flowcache_mru(flowcachep,flowpp) != FLOW_SUCCESS) { /* something's wrong because we just added this thing!\n */ flow_printf("Unable to find a key I just added!\n"); return FLOW_BADJUJU; } if(init_flowdata(flowcachep, *flowpp)) { return FLOW_BADJUJU; } return FLOW_SUCCESS; case SFXHASH_NOMEM: return FLOW_ENOMEM; case SFXHASH_INTABLE: default: return FLOW_EINVALID; }}/** * Get the most recently used flow from the cache * * @param flowcachep flow cache to operate on * @param flowp where to put the flow * * @return FLOW_SUCCESS on success */static INLINE int flowcache_mru(FLOWCACHE *flowcachep, FLOW **flowpp){ if(!flowcachep || !flowpp) return FLOW_EINVALID; *flowpp = sfxhash_mru(flowcachep->ipv4_table); if(*flowpp == NULL) return FLOW_NOTFOUND;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -