前言
第一章节介绍了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; }
结果 :
总结
提示:这里对文章进行总结: