dpdk-3.hash表CURD

参考资料

dpdk第三课------hash表增删改查的使用
Hash Library
rte_hash.h

源码

c 复制代码
// 五元组
struct flow_key {
	uint32_t ip_src; 	//src address
	uint32_t ip_dst;	//dst address
	uint16_t port_src;	//src port
	uint16_t port_dst;	//dst port
	uint8_t proto;		//protocol
}__rte_packed;
// _rte_packed 强制结构体紧凑排列,无内存空洞

// 初始化
static void
init_test_flow_key(struct flow_key *key)
{
	key->ip_src = RTE_IPV4(0x03, 0x02, 0x01, 0x00);
	key->ip_dst = RTE_IPV4(0x07, 0x06, 0x05, 0x04);
	key->port_src = 0x0908;
	key->port_dst = 0x0b0a;
	key->proto = 15;
}

/* 哈希表参数配置 */
struct rte_hash_parameters params = {
    .name = "flow_table",          // 哈希表名称(用于调试和区分多个表)
    .entries = 64,                 // 哈希表最大容量(64个条目)
    .key_len = sizeof(struct flow_key),  // 密钥长度(5元组的字节数:4+4+2+2+1=13字节)
    .hash_func = rte_jhash,        // 哈希函数(DPDK内置的Jenkins哈希,速度快)
    .hash_func_init_val = 0,       // 哈希函数初始值(用于自定义哈希结果)
    .socket_id = 0,                // 内存分配的NUMA节点(0表示第一个节点)
};

int main(int argc, char **argv)
{
    int ret;
    struct rte_hash *hash_table = NULL;
    /* init EAL */
    ret = rte_eal_init(argc, argv);
    
    // 初始化key
    struct flow_key firstKey;
    init_test_flow_key(&firstKey);
    
    /* 创建hash表 */
    hash_table = rte_hash_create(&params);
    
    /* hash表插入key */
    int pos = rte_hash_add_key(hash_table, &firstKey);
    if (pos < 0) {
        printf("ERROR: Cannot add key to hash table: %s\n", strerror(-pos));
        goto cleanup;
    }

    /* hash表查询key */
    pos = rte_hash_lookup(hash_table, &firstKey);
    if (pos < 0) {
        printf("ERROR: Cannot lookup key in hash table: %s\n", strerror(-pos));
        goto cleanup;
    }

    /* 初始化相同的key */
    struct flow_key secondKey;
    init_test_flow_key(&secondKey);
    
    // 查询key
    pos = rte_hash_lookup(hash_table, &secondKey);
    if (pos < 0) {
        printf("ERROR: Cannot lookup session key in hash table: %s\n", strerror(-pos));
        /* calculate the hash of the session key */
        uint32_t hashNow = rte_jhash(&secondKey, sizeof(struct flow_key), 0);
        printf("INFO: Hash of session key: %u\n", hashNow);
        uint32_t hashBefore = rte_jhash(&firstKey, sizeof(struct flow_key), 0);
        printf("INFO: Hash of original key: %u\n", hashBefore);
        goto cleanup;
    }

    /* hash表删除key */
    pos = rte_hash_del_key(hash_table, &firstKey);
    if (pos < 0) {
        printf("ERROR: Cannot delete key from hash table: %s\n", strerror(-pos));
        goto cleanup;
    }

    printf("INFO: Hash table operations completed successfully\n");

cleanup:
    /* clean up resources */
    if (hash_table != NULL) {
        rte_hash_free(hash_table);
        printf("INFO: Hash table successfully freed\n");
    }
    rte_eal_cleanup();
    return (hash_table == NULL) ? -1 : 0;
}

哈希表参数配置

c 复制代码
struct rte_hash_parameters params = {
    .name = "flow_table",          // 哈希表名称(用于调试和区分多个表)
    .entries = 64,                 // 哈希表最大容量(64个条目)
    .key_len = sizeof(struct flow_key),  // 密钥长度(5元组的字节数:4+4+2+2+1=13字节)
    .hash_func = rte_jhash,        // 哈希函数(DPDK内置的Jenkins哈希,速度快)
    .hash_func_init_val = 0,       // 哈希函数初始值(用于自定义哈希结果)
    .socket_id = 0,                // 内存分配的NUMA节点(0表示第一个节点)
};

哈希表核心操作

操作 函数 功能与返回值说明
创建哈希表 rte_hash_create params配置创建哈希表,返回struct rte_hash*指针;失败返回 NULL。
添加密钥 rte_hash_add_key 将 5 元组密钥加入哈希表,返回 "密钥在表中的索引(pos≥0)";失败返回负数(如 - ENOSPC)。
查找密钥 rte_hash_lookup 查找密钥是否存在,返回 "索引(pos≥0)";不存在返回 - ENOENT。
删除密钥 rte_hash_del_key 从表中删除密钥,返回 "被删除密钥的索引(pos≥0)";失败返回负数。
释放哈希表 rte_hash_free 释放哈希表占用的内存资源,无返回值。

如果没有 _rte_packed

编译器默认会为结构体成员添加填充字节,目的是让成员地址满足 "对齐要求"(如 uint32_t 通常需要 4 字节对齐,uint16_t 需要 2 字节对齐),以提升 CPU 访问效率。但在哈希计算等场景中,填充字节会破坏数据的 "完整性"。

如果存在填充字节:

  • 填充字节的内容是未定义的(可能是随机值、内存残留值等)。
  • 即使两个 flow_key 的 5 元组成员完全相同(ip_srcip_dst 等均一致),它们的填充字节也可能不同,导致:
    • rte_jhash 计算出的哈希值不同(因为输入的二进制内容不同)。
    • 哈希表查找时,会认为这两个键是不同的(即使 5 元组相同),最终导致 "添加的键无法被查到"。
相关推荐
Data_Adventure3 小时前
从 TypeScript 视角读懂 Java 和 TS 类中 new 自己的区别
后端
起这个名字3 小时前
Langchain4j Rag 知识库教程
java·后端
钟离墨笺3 小时前
Go语言-->Goroutine 详细解释
开发语言·后端·golang
用户68545375977693 小时前
🧪 设计一个全链路压测系统:战前的演习!
后端
Yeats_Liao4 小时前
Go Web 编程快速入门 11 - WebSocket实时通信:实时消息推送和双向通信
前端·后端·websocket·golang
R.lin4 小时前
使用注解将日志存入Elasticsearch
java·大数据·后端·elasticsearch·中间件
用户0806765692534 小时前
蓝桥云课-罗勇军算法精讲课(Python版)视频教程
后端
用户0806765692534 小时前
C#.NET高级班进阶VIP课程
后端
用户401426695854 小时前
Pandas数据分析实战(完结)
后端