1 某xx示例代码 dpdk 18.02
/* 使用dpdk hash 接口 */
#if 1
#include <arpa/inet.h>
#include <rte_common.h>
#include <rte_memory.h>
#include <rte_rwlock.h>
#include <rte_hash.h>
#include <rte_jhash.h>
#include <rte_mempool.h>
#define ALARM_SUPPRESS_ENTRY_CNT 4096 /* 支持4096个抑制节点 */
#define ALARM_SUPPRESS_INTERVAL 60 /* 60秒只需要同一对象告警1次 */
#define ALARM_SUPPRESS_NODE_OT 60 /* 告警抑制节点的超时时间为60秒 */
/* 告警抑制节点数据 */
typedef struct alarm_suppress_data
{
uint64_t last_export_ts_sec; /* 告警最后上报时间 */
uint64_t last_update_ts_sec; /* 节点最后更新时间 */
}ALARM_SUPPRESS_DATA_T;
/* 告警抑制节点key */
typedef struct alarm_suppress_key
{
/* key */
struct in_addr address_un_ip4; /* 告警对象的ip */
uint32_t sid; /* 告警命中的规则id */
}ALARM_SUPPRESS_KEY_T;
/* 告警抑制表 */
typedef struct alarm_suppress_tbl
{
rte_rwlock_t rwlock; /* 表锁 */
struct rte_hash *suppress_hash; /* 抑制表 */
struct rte_mempool *mp; /* data的缓存池:SP|SC */
}ALARM_SUPPRESS_TBL_T;
static ALARM_SUPPRESS_TBL_T g_alarm_suppress_tbl = {0};
/*****************************************************
函数名: cleanup_alarm_suppress_tbl
功能 : 删除超时的告警抑制节点
入参 : now_sec - 调用时间:秒
出参 : 无
返回值: 无
作者 :
时间 : 2023-08-08
说明 : 非线程安全
******************************************************/
static inline int cleanup_alarm_suppress_tbl(uint64_t now_sec)
{
struct rte_hash *tbl = g_alarm_suppress_tbl.suppress_hash;
struct rte_mempool *mp = g_alarm_suppress_tbl.mp;
ALARM_SUPPRESS_KEY_T *key;
ALARM_SUPPRESS_DATA_T *data;
uint32_t next = 0;
/* 遍历告警抑制表 */
while ( rte_hash_iterate(tbl, (const void**)&key, (void**)&data, &next) >= 0 ) {
/* 超时删除 */
if ( data->last_update_ts_sec + ALARM_SUPPRESS_NODE_OT < now_sec ) {
rte_mempool_put(mp, data);
rte_hash_del_key(tbl, key);
}
}
}
/*****************************************************
函数名 : alarm_suppress_now
功能 : 告警是否抑制
入参 : ipv4 - 告警对象的ip地址(ipv4)
sid - 告警对应的命中规则id
now_sec - 告警时间:秒
出参 : 无
返回值: 不抑制返回0,抑制返回1
作者 :
时间 : 2023-08-08
说明 : 1.暂只支持ipv4
2.有锁,确保多线程安全
******************************************************/
int alarm_suppress_now(struct in_addr *ipv4, uint32_t sid, uint64_t now_sec)
{
int ret;
struct rte_hash *tbl = g_alarm_suppress_tbl.suppress_hash;
struct rte_mempool *mp = g_alarm_suppress_tbl.mp;
ALARM_SUPPRESS_KEY_T key;
ALARM_SUPPRESS_DATA_T *data;
ALARM_SUPPRESS_DATA_T *add_data;
if ( unlikely(NULL == ipv4
|| 0 == now_sec) )
return 1;
memcpy(&key.address_un_ip4, ipv4, sizeof(struct in_addr));
key.sid = sid;
rte_rwlock_write_lock(&g_alarm_suppress_tbl.rwlock);
ret = rte_hash_lookup_data(tbl, &key, (void**)&data);
/* 查询失败:不抑制,添加节点 */
if ( ret < 0 ) {
/* 获取新节点:失败则不抑制并清理超时节点 */
ret = rte_mempool_get(mp, (void**)&add_data);
if ( 0 != ret ) {
printf("[0]add %u failed and alarm continue yes at ts:%lu\n",
key.address_un_ip4.s_addr,
now_sec);
cleanup_alarm_suppress_tbl(now_sec);
rte_rwlock_write_unlock(&g_alarm_suppress_tbl.rwlock);
return 0;
}
/* 填充新节点并加入抑制表 */
add_data->last_export_ts_sec = now_sec;
add_data->last_update_ts_sec = now_sec;
rte_hash_add_key_data(tbl, &key, add_data);
printf("[1]add %u ok and alarm up at ts:%lu\n",
key.address_un_ip4.s_addr,
now_sec);
rte_rwlock_write_unlock(&g_alarm_suppress_tbl.rwlock);
return 0;
}
/* 查询成功+非抑制时效:不抑制,更新节点 */
else if ( data->last_export_ts_sec + ALARM_SUPPRESS_INTERVAL < now_sec ) {
data->last_update_ts_sec = now_sec;
data->last_export_ts_sec = now_sec;
rte_rwlock_write_unlock(&g_alarm_suppress_tbl.rwlock);
printf("[3]another 60 sec, alarm %u up again at ts:%lu\n",
key.address_un_ip4.s_addr,
now_sec);
return 0;
}
/* 查询成功+抑制时效:抑制,更新节点 */
else {
data->last_update_ts_sec = now_sec;
rte_rwlock_write_unlock(&g_alarm_suppress_tbl.rwlock);
printf("[2]during 60 sec, alarm %u no at ts:%lu\n",
key.address_un_ip4.s_addr,
now_sec);
return 1;
}
}
/*****************************************************
函数名: create_alarm_suppress_tbl
功能 : 创建告警抑制哈希表
入参 : 无
出参 : 无
返回值: 成功返回0,否则返回-1
作者 :
时间 : 2023-08-08
说明 : 1.抑制表与缓存池,大小一样
******************************************************/
int create_alarm_suppress_tbl(void)
{
struct rte_hash_parameters params = {0};
/* 设置抑制表参数 */
params.name = "alarm_suppress_tbl";
params.entries = 8;
params.reserved = 0;
params.key_len = sizeof(ALARM_SUPPRESS_KEY_T);
params.hash_func = rte_jhash;
params.hash_func_init_val = 0;
params.socket_id = SOCKET_ID_ANY;
/* 初始锁/抑制表/缓存池 */
rte_rwlock_init(&g_alarm_suppress_tbl.rwlock);
g_alarm_suppress_tbl.suppress_hash = rte_hash_create(¶ms);
if ( NULL == g_alarm_suppress_tbl.suppress_hash ) {
return -1;
}
g_alarm_suppress_tbl.mp = rte_mempool_create("alarm_suppress_mp",
8,
sizeof(ALARM_SUPPRESS_DATA_T),
0, 0,
NULL, NULL, NULL, NULL,
SOCKET_ID_ANY, MEMPOOL_F_SP_PUT|MEMPOOL_F_SC_GET);
if ( NULL == g_alarm_suppress_tbl.mp ) {
return -1;
}
return 0;
}
#endif
2 说明 dpdk 18.02
- rte_hash_add_key_data() :
添加
- 将 key-data 对存入hash表
- key 拷贝复制:局部变量–>拷贝存入hash
- data 仅存储指针:申请的空间–>放到hash
- 最好来自mempool;
- 在rte_hash_iterate && rte_del_key 时,手动释放data,避免空间满
- 返回值:小于0,添加失败
- rte_hash_lookup_data():
查询
- 返回值:小于0,查找失败
- 查到的data,就是存储的指针
- 最好来自mempool
- 这样保证能访问的之前存储的数据
- 这里存储指针,提供自定义的可能,具有通用性
- rte_hash_iterate():
遍历
- 返回值:大于等于0,当前节点可用;小于0,遍历结束
- 能配合while 进行hash表的遍历
- 可用于超时删除、打印表等
3 参考资料