Hash 系列文章目录
文章目录
前言
第一章节介绍了DPDK的相关原理,和DPDK采用Cuckoo hash 相关性能指标。本章节主要是介绍DPDK hash 常用的 api 接口。
一、DPDK Hash
DPDK Hash Libary 提供函数主要是实现增加(add),删除(del), 查找(lookup),遍历(iterate)等功能。
二、DPDK hash 常用的API接口
1.DPDK 结构体
创建Hash 使用的参数结构体 如下:
/**
* Parameters used when creating the hash table.
*/
struct rte_hash_parameters {
const char *name; /**< Name of the hash. */ //此名字具备唯一性, 在dpdk 中hash ,ring 等都需要唯一性名字
uint32_t entries; /**< Total hash table entries. */ // 创建的Hash 表容量,支持多少个条目
uint32_t reserved; /**< Unused field. Should be set to 0 */ // 保留
uint32_t key_len; /**< Length of hash key.*/ //每个Hash key 的长度。Hash 表中的Hash key 长度是统一的,有此处设置大小。
rte_hash_function hash_func; /**< Primary Hash function used to calculate hash. */ cuckoo Hask 需要两个Hash function,在这里设置Cuckoo Hash的主计算Function
uint32_t hash_func_init_val; /**< Init value used by hash_func. */
int socket_id; /**< NUMA Socket ID for memory. */ 此处表示Hash创建在那个物理socket_id 上。
uint8_t extra_flag; /**< Indicate if additional parameters are present. */
};
2. DPDK 常用接口
DPDK Hash API常用接口如下:
DPDK Hash API 大部分在<rte_hash.h> 中
// Hash table 的创建函数
struct rte_hash *rte_hash_create(const struct rte_hash_parameters *params);
// Hash add API 提供了四种
// hash_header + key
int32_t rte_hash_add_key(const struct rte_hash *h, const void *key);
// Hash_header + key + data. 在对应的Hash 表中存储数据data.
int rte_hash_add_key_data(const struct rte_hash *h, const void *key, void *data);
// Hash_headr +key + hask_function(slaver function)
int32_t rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key, hash_sig_t sig);
// Hash_hader+key+
int32_t rte_hash_add_key_with_hash_data(const struct rte_hash *h, const void *key,hash_sig_t sig, void *data);
// 删除
// 根据key 删除
int32_t rte_hash_del_key(const struct rte_hash *h, const void *key);
// 根据key和slave Hash function vale
int32_t rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key, hash_sig_t sig);
// 重置真个hash table
void rte_hash_reset(struct rte_hash *h);
// 遍历整个表
int32_t rte_hash_iterate(const struct rte_hash *h, const void **key, void **data, uint32_t *next);
三、DPDK 提供的Hash 算法
DPDK hash 提供了默认的默认的Hash 计算primary function. 如果不设置h->hash_func 就使用初始化默认的hash 函数
Hash 计算的slave function 可以使用rte_hash_hash(const struct rte_hash *h, const void *key) 获取。
Hash 计算函数可以自己定义: 比如l3fwd中。哈希函数就是自定义的。
四、DPDK Hash Demo
#include <stdio.h>
#include <arpa/inet.h>
#include <rte_eal.h>
#include <rte_ethdev.h>
//#include <rte_log.h>
#include <rte_hash.h>
#include <rte_jhash.h>
// hash表,也就是实现增删改查等功能
#define HASH_ENTRI_MAXNUM 1<<12
#define HUSH_KEY_COUNT 1<< 4
// 创建Hash key。 此处采用TUPLE5
struct net_key {
uint32_t sip;
uint32_t dip;
uint16_t sport;
uint16_t dport;
char proto;
};
static void print_key (struct net_key *key) {
printf("sip: %x dip: %x sport: %x dport %x proto:%d \n",
key->sip, key->dip, key->sport, key->dport, key->proto);
}
// DPDK 创建表,队列等都需要自定义名字
static struct rte_hash * create_hash_table(const char *name){
struct rte_hash_parameters *param = (struct rte_hash_parameters *) malloc(sizeof(struct rte_hash_parameters));
if (!param) return NULL;
param->name = name;
param->entries = HASH_ENTRI_MAXNUM;
param->key_len = sizeof(struct net_key);
param->hash_func = rte_jhash; // hash 函数
param->hash_func_init_val = 0;
param->socket_id =rte_socket_id(); // 进行NUMA, 这个是表示每一块内存上的寻址。
struct rte_hash *hash = rte_hash_create(param);
if (hash == NULL) {
//RTE_LOG(INFO, Hash, "========================\n");
}
return hash;
}
//DPDK 添加方式有四种
int main(int argc, char *argv[]){
// DPDK 环境初始化
rte_eal_init(argc, argv);
int i = 0;
uint32_t net_sip;
uint32_t net_dip;
uint16_t sport;
uint16_t dport;
inet_pton(AF_INET,"192.168.1.1",&net_sip);
inet_pton(AF_INET,"192.168.2.1", &net_dip);
sport = htons(5000);
dport = htons(6000);
struct rte_hash *hash = create_hash_table("cuckoo hash table");
for (i = 0; i < HUSH_KEY_COUNT; i++){
struct net_key *nk = malloc(sizeof(struct net_key));
nk->sip = net_sip + i;
nk->dip = net_dip + i;
nk->sport = sport+ i;
nk->dport = dport + i;
nk->proto = i % 2;
// key
// key hash
// key data+
// key hash, data
if(i % 4 == 0) {
//rte_hash_add_key(hash, nk);
}else if(i % 4 == 1){ // 第二种添加
hash_sig_t key2 = rte_hash_hash(hash, nk);
rte_hash_add_key_with_hash(hash, nk, key2);
}
else if (i %4 == 2){ // 第三种添加
uint32_t* tmpdata = (uint32_t *)malloc(sizeof(uint32_t));
*tmpdata = i;
rte_hash_add_key_data(hash, nk, (void *)tmpdata);
}else {
hash_sig_t key4 = rte_hash_hash(hash, nk);
uint32_t* tmp = (uint32_t *)malloc(sizeof(uint32_t));
*tmp= i;
rte_hash_add_key_with_hash_data(hash, nk, key4, (void *)tmp);
}
}
#if 0
for (i = 0;i < HUSH_KEY_COUNT;i ++) {
struct net_key *nk = malloc(sizeof(struct net_key));
nk->sip = net_sip + i;
nk->dip = net_dip + i;
nk->sport = sport+ i;
nk->dport = dport + i;
nk->proto = i % 2;
int idx = rte_hash_lookup(hash, nk);
printf("hash lookup --> sip: %x, idx: %d\n", nk->sip, idx);
rte_hash_del_key(hash, nk);
free(nk);
}
#endif
struct net_key *key = NULL;
void *value = NULL;
uint32_t next =0;
while (rte_hash_iterate( hash, (const void **)&key, &value,&next) >= 0){
print_key(key);
if (value != NULL)
printf("value : %u \n", *(uint32_t*)value);
}
return 0;
}
结果 :
总结
提示:这里对文章进行总结: