add helper to build (red/black) trees from a key that is a vector of guin32 arrays.

test this functionality by calling these vector insert/lookup tree functions from the nfs dissector for when filehandles are used as a key.

these vector functions could also be used to efficiently store conversations :
se_tree_key_t[6] = {
	{ addr_len/4,   &src_addr },
	{ addr_len/4,	&dst_addr },
	{ 1,		&src_port32 },
	{ 1,		&dst_port32 },
	{ 1,		&protocol32 },
	{ 0, NULL }
}


(the nfs dissector needs a LOT of work. It is very painful to work with 
very large nfs traces with all the memory it wastes (and eats) as well as how slow all the tables make it)



svn path=/trunk/; revision=17477
This commit is contained in:
Ronnie Sahlberg 2006-03-06 10:25:19 +00:00
parent 7f2bd47f5e
commit 745994c364
3 changed files with 156 additions and 21 deletions

View File

@ -521,7 +521,7 @@ static GHashTable *nfs_name_snoop_unmatched = NULL;
static GHashTable *nfs_name_snoop_matched = NULL;
static GHashTable *nfs_name_snoop_known = NULL;
static se_tree_t *nfs_name_snoop_known = NULL;
static gint
nfs_name_snoop_matched_equal(gconstpointer k1, gconstpointer k2)
@ -608,15 +608,6 @@ nfs_name_snoop_init(void)
nfs_name_snoop_matched=g_hash_table_new(nfs_name_snoop_matched_hash,
nfs_name_snoop_matched_equal);
}
if (nfs_name_snoop_known != NULL) {
g_hash_table_foreach_remove(nfs_name_snoop_known,
nfs_name_snoop_unmatched_free_all, NULL);
} else {
/* The fragment table does not exist. Create it */
nfs_name_snoop_known=g_hash_table_new(nfs_name_snoop_matched_hash,
nfs_name_snoop_matched_equal);
}
}
void
@ -780,12 +771,16 @@ nfs_name_snoop_fh(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int fh_of
nns=g_hash_table_lookup(nfs_name_snoop_matched, &key);
if(nns){
nfs_name_snoop_key_t *k;
k=se_alloc(sizeof(nfs_name_snoop_key_t));
k->key=pinfo->fd->num;
k->fh_length=nns->fh_length;
k->fh=nns->fh;
g_hash_table_insert(nfs_name_snoop_known, k, nns);
guint32 fhlen;
se_tree_key_t fhkey[3];
fhlen=nns->fh_length;
fhkey[0].length=1;
fhkey[0].key=&fhlen;
fhkey[1].length=fhlen/4;
fhkey[1].key=nns->fh;
fhkey[2].length=0;
se_tree_insert32_array(nfs_name_snoop_known, &fhkey[0], nns);
if(nfs_file_name_full_snooping){
unsigned char *name=NULL, *pos=NULL;
@ -802,11 +797,17 @@ nfs_name_snoop_fh(packet_info *pinfo, proto_tree *tree, tvbuff_t *tvb, int fh_of
/* see if we know this mapping */
if(!nns){
key.key=pinfo->fd->num;
key.fh_length=fh_length;
key.fh=(const unsigned char *)tvb_get_ptr(tvb, fh_offset, fh_length);
guint32 fhlen;
se_tree_key_t fhkey[3];
nns=g_hash_table_lookup(nfs_name_snoop_known, &key);
fhlen=fh_length;
fhkey[0].length=1;
fhkey[0].key=&fhlen;
fhkey[1].length=fhlen/4;
fhkey[1].key=tvb_get_ptr(tvb, fh_offset, fh_length);
fhkey[2].length=0;
nns=se_tree_lookup32_array(nfs_name_snoop_known, &fhkey[0]);
}
/* if we know the mapping, print the filename */
@ -8826,6 +8827,7 @@ proto_register_nfs(void)
"Fhandle filters finds both request/response",
"With this option display filters for nfs fhandles (nfs.fh.{name|full_name|hash}) will find both the request and response packets for a RPC call, even if the actual fhandle is only present in one of the packets",
&nfs_fhandle_reqrep_matching);
nfs_name_snoop_known=se_tree_create(SE_TREE_TYPE_RED_BLACK);
register_init_routine(nfs_name_snoop_init);
register_init_routine(nfs_fhandle_reqrep_matching_init);
}

View File

@ -718,7 +718,6 @@ void* ep_stack_pop(ep_stack_t stack) {
/* routines to manage se allocated red-black trees */
se_tree_t *se_trees=NULL;
/* keylen is length of key in number of guint32 fields */
se_tree_t *
se_tree_create(int type)
{
@ -1030,3 +1029,70 @@ se_tree_insert32(se_tree_t *se_tree, guint32 key, void *data)
}
/* When the se data is released, this entire tree will dissapear as if it
* never existed including all metadata associated with the tree.
*/
se_tree_t *
se_tree_create_non_persistent(int type)
{
se_tree_t *tree_list;
tree_list=se_alloc(sizeof(se_tree_t));
tree_list->next=NULL;
tree_list->type=type;
tree_list->tree=NULL;
return tree_list;
}
/* insert a new node in the tree. if this node matches an already existing node
* then just replace the data for that node */
void
se_tree_insert32_array(se_tree_t *se_tree, se_tree_key_t *key, void *data)
{
se_tree_t *next_tree;
if((key[0].length<1)||(key[0].length>100)){
DISSECTOR_ASSERT_NOT_REACHED();
}
if((key[0].length==1)&&(key[1].length==0)){
se_tree_insert32(se_tree, *key[0].key, data);
return;
}
next_tree=se_tree_lookup32(se_tree, *key[0].key);
if(!next_tree){
next_tree=se_tree_create_non_persistent(se_tree->type);
se_tree_insert32(se_tree, *key[0].key, next_tree);
}
if(key[0].length==1){
key++;
} else {
key[0].length--;
key[0].key++;
}
se_tree_insert32_array(next_tree, key, data);
}
void *
se_tree_lookup32_array(se_tree_t *se_tree, se_tree_key_t *key)
{
se_tree_t *next_tree;
if((key[0].length<1)||(key[0].length>100)){
DISSECTOR_ASSERT_NOT_REACHED();
}
if((key[0].length==1)&&(key[1].length==0)){
return se_tree_lookup32(se_tree, *key[0].key);
}
next_tree=se_tree_lookup32(se_tree, *key[0].key);
if(!next_tree){
return NULL;
}
if(key[0].length==1){
key++;
} else {
key[0].length--;
key[0].key++;
}
se_tree_lookup32_array(next_tree, key);
}

View File

@ -190,8 +190,75 @@ typedef struct _se_tree_t {
} se_tree_t;
extern se_tree_t *se_trees;
/* This function is used to create a se based tree with monitoring.
* When the SE heap is released back to the system the pointer to the
* tree is automatically reset to NULL.
*
* type is : SE_TREE_TYPE_RED_BLACK for a standard red/black tree.
*/
se_tree_t *se_tree_create(int type);
/* This function is used to insert a node indexed by a guint32 key value.
* The data pointer should be allocated by SE allocators so that the
* data will be released at the same time as the tree itself is destroyed.
*/
void se_tree_insert32(se_tree_t *se_tree, guint32 key, void *data);
/* This function will look up a node in the tree indexed by a guint32 integer
* value.
*/
void *se_tree_lookup32(se_tree_t *se_tree, guint32 key);
/* This function is similar to the se_tree_create() call but with the
* difference that when the se memory is release everything including the
* pointer to the tree itself will be released.
* This tree will not be just reset to zero it will be completely forgotten
* by the allocator.
* Use this function for when you want to store the pointer to a tree inside
* another structure that is also se allocated so that when the structure is
* released, the tree will be completely released as well.
*/
se_tree_t *se_tree_create_non_persistent(int type);
typedef struct _se_tree_key_t {
guint32 length; /*length in guint32 words */
guint32 *key;
} se_tree_key_t;
/* This function is used to insert a node indexed by a sequence of guint32
* key values.
* The data pointer should be allocated by SE allocators so that the
* data will be released at the same time as the tree itself is destroyed.
*
* If you use ...32_array() calls you MUST make sure that every single node
* you add to a specific tree always has a key of exactly the same number of
* keylen words or things will most likely crash. Or at least that every single
* item that sits behind the same top level node always have exactly the same
* number of words.
*
* One way to guarantee this is the way that NFS does this for the
* nfs_name_snoop_known tree which holds filehandles for both v2 and v3.
* v2 filehandles are always 32 bytes (8 words) while v3 filehandles can have
* any length (though 32bytes are most common).
* The NFS dissector handles this by providing a guint32 containing the length
* as the very first item in this vector :
*
* se_tree_key_t fhkey[3];
*
* fhlen=nns->fh_length;
* fhkey[0].length=1;
* fhkey[0].key=&fhlen;
* fhkey[1].length=fhlen/4;
* fhkey[1].key=nns->fh;
* fhkey[2].length=0;
*/
void se_tree_insert32_array(se_tree_t *se_tree, se_tree_key_t *key, void *data);
/* This function will look up a node in the tree indexed by a sequence of
* guint32 integer values.
*/
void *se_tree_lookup32_array(se_tree_t *se_tree, se_tree_key_t *key);
#endif /* emem.h */