#include #include #include #include "hashtable.h" /* see linux/include/linux/jhash.h for details */ #define JHASH_GOLDEN_RATIO 0x9e3779b9 #define __jhash_mix(a, b, c) \ { \ a -= b; a -= c; a ^= (c>>13); \ b -= c; b -= a; b ^= (a<<8); \ c -= a; c -= b; c ^= (b>>13); \ a -= b; a -= c; a ^= (c>>12); \ b -= c; b -= a; b ^= (a<<16); \ c -= a; c -= b; c ^= (b>>5); \ a -= b; a -= c; a ^= (c>>3); \ b -= c; b -= a; b ^= (a<<10); \ c -= a; c -= b; c ^= (b>>15); \ } struct hash_table * create_hash(uint32_t buckets) { struct hash_table *table; uint32_t i; table = malloc(sizeof(struct hash_table) + (sizeof(struct hash_entry *) * buckets)); if (table == NULL) return NULL; for (i = 0; i < buckets; i++) table->bucket[i] = NULL; table->buckets = buckets; table->hash_rnd = 0x56789ABC; pthread_mutex_init(&table->mutex, NULL); return table; } void purge_hash(struct hash_table *table, void (*callback)(struct hash_entry *entry, void *privdata), void *privdata) { uint32_t i; pthread_mutex_lock(&table->mutex); for (i = 0; i < table->buckets; i++) { struct hash_entry *entry = table->bucket[i]; while (entry != NULL) { struct hash_entry *tmp = entry; if (callback != NULL) callback(entry, privdata); entry = entry->next; free(tmp); } table->bucket[i] = NULL; } pthread_mutex_unlock(&table->mutex); } void destroy_hash(struct hash_table *table) { purge_hash(table, NULL, NULL); pthread_mutex_destroy(&table->mutex); free(table); } static uint32_t calc_hashkey(struct hash_entry *entry, uint32_t initval) { uint32_t a = entry->src_ip; uint32_t b = entry->protonum; uint32_t c = entry->dst_port; a += JHASH_GOLDEN_RATIO; b += JHASH_GOLDEN_RATIO; c += initval; __jhash_mix(a, b, c); return c; } static int cmp_entry(struct hash_entry *a, struct hash_entry *b) { return (a->src_ip ^ b->src_ip) | (a->protonum ^ b->protonum) | (a->dst_port ^ b->dst_port); } void hash_add(struct hash_table *table, struct hash_entry *entry) { uint32_t key = calc_hashkey(entry, table->hash_rnd) % table->buckets; pthread_mutex_lock(&table->mutex); struct hash_entry *search = table->bucket[key]; /* search collision-list */ while (search != NULL) { if (cmp_entry(entry, search) == 0) { /* add values */ search->src_bytes += entry->src_bytes; search->dst_bytes += entry->dst_bytes; search->count++; pthread_mutex_unlock(&table->mutex); /* free entry */ free(entry); return; } search = search->next; } /* insert new bucket */ entry->count = 1; entry->next = table->bucket[key]; table->bucket[key] = entry; pthread_mutex_unlock(&table->mutex); }