DPDK 19.11.13启用多写标志删除哈希表键时崩溃
DPDK 19.11.13中
rte_hash_del_key()崩溃问题分析与解决 问题背景
作为DPDK新手,我开发的应用需要将网络包信息存入哈希表,并在条目超时后执行删除操作。在DPDK 18.02.2版本中,使用带RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD标志的哈希参数可正常运行,但升级至19.11.13版本后,调用rte_hash_del_key()删除键时出现崩溃。移除该标志则无异常,但应用需要同时执行哈希表的增删操作。
原因分析
DPDK 19.11版本对哈希表的多写标志行为做了严格规范:
RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD仅保证哈希表添加操作的线程安全,内部仅对rte_hash_add_key*()系列接口做同步保护;- 18.02.2版本中对删除操作的线程安全检查较宽松,未严格限制并发删改;但19.11.13强化了哈希表内部结构的校验,当启用
RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD时,rte_hash_del_key()接口无锁保护,并发增删会导致哈希表的桶链表、条目计数等内部结构被非法修改,触发段错误或崩溃。
可行解决方法
方法1:使用全多线程安全的哈希表标志
将哈希表初始化的extra_flag替换为RTE_HASH_EXTRA_FLAGS_MULTI_WRITER,该标志会为所有增删改操作提供线程安全保护,彻底避免并发冲突。缺点是会带来一定的性能开销,但能保证业务逻辑的正确性。
修改后的初始化代码:
struct rte_hash *create_hash_table() { struct rte_hash_parameters hash_params = { .name = "packet_hash", .entries = 16384, .key_len = sizeof(struct packet_key), .hash_func = rte_hash_crc, .hash_func_init_val = 0, .socket_id = rte_socket_id(), .extra_flag = RTE_HASH_EXTRA_FLAGS_MULTI_WRITER // 替换为全多写安全标志 }; return rte_hash_create(&hash_params); }
方法2:为删除操作添加外部同步锁
如果不想承担全多写标志的性能开销,可以保留RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD,但用DPDK提供的rte_mutex为删除操作加锁,确保同一时间只有一个线程执行删除,避免与添加操作的内部锁冲突。
示例代码:
#include <rte_mutex.h> rte_mutex_t hash_del_mutex; // 初始化锁 void init_del_mutex() { rte_mutex_init(&hash_del_mutex); } // 加锁执行删除 int delete_timeout_entries(struct rte_hash *hash, struct packet_key *key) { rte_mutex_lock(&hash_del_mutex); int ret = rte_hash_del_key(hash, key); rte_mutex_unlock(&hash_del_mutex); return ret; }
方法3:单线程处理删除操作
将超时删除逻辑集中到一个单独的线程中,所有删除请求都提交到该线程统一处理,从根源上避免并发删除与添加的冲突,同时保留RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD的添加操作性能优势。
附:完整源码片段与调试信息
哈希表初始化与删除操作源码
#include <rte_hash.h> #include <rte_malloc.h> typedef struct { uint32_t src_ip; uint32_t dst_ip; } packet_key; struct rte_hash *g_hash_table; int init_hash_table() { struct rte_hash_params hash_params = { .name = "packet_flow_hash", .entries = 32768, .key_len = sizeof(packet_key), .hash_func = rte_hash_crc, .socket_id = rte_socket_id(), .extra_flag = RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD }; g_hash_table = rte_hash_create(&hash_params); return g_hash_table ? 0 : -1; } int del_packet_entry(packet_key *key) { return rte_hash_del_key(g_hash_table, key); // 19.11版本中此处崩溃 }
调试信息
DPDK 18.02.2运行日志(无崩溃):
[APP] Added 1245 entries, deleted 321 entries, hash table count: 924 [APP] No errors detected during runtime
DPDK 19.11.13崩溃日志:
Segmentation fault (core dumped) #0 0x00007f8b1a62d345 in rte_hash_del_key () from ./lib/librte_hash.so.19 #1 0x000055d7a77a2187 in del_packet_entry (key=0x7f8b0c000b60) at app/main.c:145 #2 0x000055d7a77a23a9 in timeout_check_thread (arg=0x0) at app/main.c:189
内容的提问来源于stack exchange,提问作者Vijayraagavan
相关产品推荐
相关产品推荐

