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 元组相同),最终导致 "添加的键无法被查到"。
相关推荐
9523632 分钟前
RabbitMQ-基础操作
java·spring boot·分布式·后端·spring·rabbitmq
柒和远方1 小时前
从审计日志到可下载证据包:事务型 Outbox、租约 fencing 与保留水位
前端·后端·架构
geovindu2 小时前
CSharp: Prototype Pattern
开发语言·后端·设计模式·.net·原型模式·创建型模式
Listen·Rain3 小时前
Springboot整合Ollama实现调用本地多模型
java·spring boot·后端
张三丰23 小时前
Agent 不只是聊天框:用 ArkUI 做一个鸿蒙任务工作台
后端
卷无止境3 小时前
从Python的cryptography库出发,从零开始理解密码学,到构建零信任网络
后端·python
Augustzero3 小时前
`co_await` 按下暂停键之后:从零看懂 C++20 协程
c++·后端
IguoChan6 小时前
4. d2l — 模型选择、欠拟合和过拟合
后端
shepherd1266 小时前
一次把 Spring MVC 文件上传参数“查没了”的排查:multipart、Filter 与 request body 的连环坑
java·后端·spring·mvc
贺国亚6 小时前
Prompt-Injection攻防与OWASP-LLM
后端