简单用如下的例子介绍哈希表数据结构,以及相关操作。
1、数据结构
/*哈希头节点*/
typedef struct _hash_head
{
unsigned elem; /* The number of elements currently in the table */
unsigned size; /* The size of the hash table */
struct hlist_head *head; /* The hash table */
spinlock_t lock ;
} hash_head_t;
hash_head_t *g_hash_head = NULL;
/*存储的数据结构:源IP+目的IP*/
typedef struct ip_addr_pair
{
__be32 src_ip;
__be32 dst_ip;
atomic_t count;
struct hlist_node hash_list;
} ip_addr_pair_t;
2、初始化
主要是分配哈希头节点存储空间,以及每个哈希节点的空间分配及初始化。
int hash_init(void)
{
struct hlist_head *hash = NULL;
unsigned int i, hash_size = nf_conntrack_max;
g_hash_head = kmalloc(sizeof(hash_head_t), GFP_KERNEL);
if (NULL == g_hash_head)
{
printk("Failed to malloc hash head in hash init.\n");
return ERROR;
}
hash = vmalloc(hash_size * sizeof(struct hlist_head));
if (NULL == hash)
{
kfree(g_hash_head);
printk("Failed to malloc hash table in hash init.\n");
return ERROR;
}
if (NULL != hash)
{
for (i = 0; i < hash_size; i++)
{
INIT_HLIST_HEAD(&hash[i]);
}
}
g_hash_head->head = hash;
g_hash_head->elem = 0;
g_hash_head->size = hash_size;
spin_lock_init(&g_hash_head->lock);
return OK;
}
3、卸载清空
void hash_exit(void)
{
unsigned i = 0;
ip_addr_pair_t *entry = NULL;
hash_head_t *head = g_hash_head;
struct hlist_node *node, *next;
spin_lock_bh(&head->lock);
for(i = 0; i < head->size; i++)
{
hlist_for_each_entry_safe(entry, node, next, &head->head[i], hash_list)
{
__hlist_del(&entry->hash_list);
head->elem--;
kfree(entry);
entry = NULL;
}
}
spin_unlock_bh(&head->lock);
if (g_hash_head)
{
vfree(g_hash_head->head);
g_hash_head->head = NULL;
kfree(g_hash_head);
g_hash_head = NULL;
}
}
4、哈希函数
static unsigned hash_fn(const void *key_param, int key_len)
{
unsigned a = 0;
unsigned b = 0;
unsigned len;
uint8_t *key = (uint8_t *) key_param;
/* Set up the internal state */
len = (unsigned) key_len;
a = len;
if (len >= 4)
{
b = key[0] + (key[1] << 8) + (key[2] << 16) + (key[3] << 24);
}
while (len >= 8)
{
a += b;
key += 4;
a += ~(a << 15);
len -= 4;
a ^= (a >> 10);
b = key[0];
a += (a << 3);
b += key[1] << 8;
a ^= (a >> 6);
b += key[2] << 16;
a += ~(a << 11);
b += key[3] << 24;
a ^= (a >> 16);
}
if (len >= 4)
{
a += b;
a += ~(a << 15);
len -= 4;
a ^= (a >> 10);
a += (a << 3);
a ^= (a >> 6);
a += ~(a << 11);
a ^= (a >> 16);
}
/* All the case statements fall through */
switch (len)
{
case 3 :
a += key[2] << 16;
case 2 :
a ^= key[1] << 8;
case 1 :
a += key[0];
default:
break;
}
return a;
}
5、元素比较函数
static bool addrPair_hash_cmp(ip_addr_pair_t *pAddrPair, ip_addr_pair_key_t *key)
{
return ((pAddrPair->src_ip == key->src_ip) && (pAddrPair->dst_ip == key->dst_ip));
}
6、哈希添加
int hash_add(ip_addr_pair_key_t *key, uint32_t mark)
{
unsigned hash = 0;
unsigned hash_index = 0;
ip_addr_pair_t *entry, *pAddrPair = NULL;
hash_head_t *head = g_hash_head;
struct hlist_node *node = NULL;
if(elem_up_limit())
return OVER_MAX;
hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
hash_index = hash % head->size;
spin_lock_bh(&head->lock);
hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
{
if (addrPair_hash_cmp(entry, key))
{
atomic_inc(&entry->count);
spin_unlock_bh(&head->lock);
return OK;
}
}
pAddrPair = kmalloc(sizeof(ip_addr_pair_t), GFP_KERNEL);
if(NULL == pAddrPair)
{
spin_unlock_bh(&head->lock);
printk("Failed kmalloc pAddrPair.\n");
return ALLOC_FAIL;
}
pAddrPair->src_ip = key->src_ip;
pAddrPair->dst_ip = key->dst_ip;
atomic_set(&pAddrPair->count, 1);
hlist_add_head(&pAddrPair->hash_list, &head->head[hash_index]);
head->elem++;
spin_unlock_bh(&head->lock);
return OK;
}
7、哈希查询
ip_addr_pair_t *hash_get(ip_addr_pair_key_t *key)
{
unsigned hash = 0;
unsigned hash_index = 0;
struct hlist_node *node = NULL;
ip_addr_pair_t *entry = NULL;
hash_head_t *head = g_hash_head;
hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
hash_index = hash % head->size;
spin_lock_bh(&head->lock);
hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
{
if (addrPair_hash_cmp(entry, key))
{
spin_unlock_bh(&head->lock);
return entry;
}
}
spin_unlock_bh(&head->lock);
return NULL;
}
8、哈希删除
int hash_remove(ip_addr_pair_key_t *key)
{
unsigned hash = 0;
unsigned hash_index = 0;
struct hlist_node *node = NULL;
ip_addr_pair_t *entry = NULL;
hash_head_t *head = g_hash_head;
hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
hash_index = hash % head->size;
spin_lock_bh(&head->lock);
hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
{
if (addrPair_hash_cmp(entry, key))
{
if(atomic_read(&entry->count) > 1)
{
atomic_dec(&entry->count);
spin_unlock_bh(&head->lock);
return COUNT_NOZERO;
}
else
{
__hlist_del(&entry->hash_list);
head->elem--;
spin_unlock_bh(&head->lock);
return OK;
}
}
}
spin_unlock_bh(&head->lock);
return NO_EXIST;
}