snmp总结四:lwip-snmp
snmp总结四:lwip-snmp
上一节讲到了在Linux的环境下基于net-snmp的SNMP代理的实现,那在单片机等资源环境受限的情况下SNMP协议解决方案呢?本节实验环境 RT-Thread5.1.0 + AT32F437ZMT7 + lwip2.1.2.
本节内容基于对 RT-Thread 系统开发有一定了解的基础上,使用《snmp总结二:MIB语法》中的完整示例 mib。
RT-Thread 内核配置使能SNMP

1 lwip-snmp 基础使用
1.1 snmp初始化
/* 修改mib2下的系统基础信息 */
snmp_mib2_set_sysdescr(sysdescr, &ocstrlen_sysdescr);
snmp_mib2_set_syscontact(syscontact, &ocstrlen_syscontact, 0);
snmp_mib2_set_sysname(sysname, &ocstrlen_sysname, 0);
snmp_mib2_set_syslocation(syslocation, &ocstrlen_syslocation, 0);
/* 设置企业OID */
snmp_set_device_enterprise_oid(&device_enterprise_oid);
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
/* 设置trap目的地址 */
snmp_trap_dst_enable(0, 1);
snmp_trap_dst_ip_set(0, &test_snmp_trap_ip);
/* 设置mib、访问共同体 */
snmp_set_mibs(&dev_mibs[0], LWIP_ARRAYSIZE(dev_mibs));
snmp_set_community("public");
snmp_set_community_write("public");
/* 初始化snmp */
snmp_init();
1.2 标量创建示例
static u32_t sensor_value[4];
/* 获取值 */
static s16_t sensor_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
/* node->oid 当前节点OID值 */
if (node->oid < 3)
sensor_value[node->oid - 1] = node->oid * 100 + rand() % 10;
*(u32_t *)value = sensor_value[node->oid - 1];
return 4;
}
/* 设置检测 */
static snmp_err_t sensor_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
s32_t *sint_ptr = (s32_t *)value;
/* 值限制范围 */
if (*sint_ptr < 100 || *sint_ptr > 600)
return SNMP_ERR_WRONGVALUE;
return SNMP_ERR_NOERROR;
}
/* 设置值 */
static snmp_err_t sensor_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
sensor_value[node->oid - 1] = *(s32_t *)value;
log_d("sensor_set oid = %d value = %d\r\n", node->oid, *(s32_t *)value);
return SNMP_ERR_NOERROR;
}
/* 标量节点定义 */
static const struct snmp_scalar_array_node_def sensor_scalars_nodes[] = {
{1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* Rsensor1 */
{2, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* Rsensor2 */
{3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* RWsensor1 */
{4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* RWsensor2 */
};
/* 创建传感标量组节点*/
const struct snmp_scalar_array_node sensor_scalars = SNMP_SCALAR_CREATE_ARRAY_NODE(2, sensor_scalars_nodes, sensor_get_value, sensor_set_test, sensor_set_value);
1.3 表类型创建示例
#define TH_SENSOR_NUM 4
static s32_t th_value[TH_SENSOR_NUM][4];
/* 表行大小区间 */
static const struct snmp_oid_range th_table_oid_ranges[] = {
{1, TH_SENSOR_NUM},
};
/* 获取当前实例 */
static snmp_err_t th_get_instance(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, struct snmp_node_instance *cell_instance)
{
LWIP_UNUSED_ARG(column);
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, th_table_oid_ranges, LWIP_ARRAYSIZE(th_table_oid_ranges)))
return SNMP_ERR_NOSUCHINSTANCE;
cell_instance->reference.u32 = row_oid[0]; /* 传递行数 */
return SNMP_ERR_NOERROR;
}
/* 获取下一个OID实例 */
static snmp_err_t th_get_next_instance(const u32_t *column, struct snmp_obj_id *row_oid, struct snmp_node_instance *cell_instance)
{
u8_t i = 0;
struct snmp_next_oid_state state;
u32_t next_oid = 0;
/* 查找下个节点 */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, &next_oid, 1);
for (i = 0; i < TH_SENSOR_NUM; i++)
{
u32_t test_oid = i + 1;
snmp_next_oid_check(&state, &test_oid, 1, NULL);
}
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS)
{
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
cell_instance->reference.u32 = *state.next_oid; /* 下个节点行OID */
return SNMP_ERR_NOERROR;
}
return SNMP_ERR_NOSUCHINSTANCE;
}
/* 获取值 */
static s16_t th_get_value(struct snmp_node_instance *instance, void *value)
{
u32_t row = instance->reference.u32;
u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
s32_t *value_s32 = (s32_t *)value;
/* 第一列索引 */
if (col == 1)
{
*value_s32 = row;
return sizeof(s32_t);
}
if (col < 4)
th_value[row - 1][col - 2] = row * 100 + col * 10 + rand() % 10 + th_value[row - 1][col];
*value_s32 = th_value[row - 1][col - 2];
return sizeof(s32_t);
}
/* 设置测试 */
static snmp_err_t th_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
{
// u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
s32_t *sint_ptr = (s32_t *)value;
if (*sint_ptr < -600 || *sint_ptr > 600)
return SNMP_ERR_WRONGVALUE;
return SNMP_ERR_NOERROR;
}
/* 设置值 */
static snmp_err_t th_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
u32_t row = instance->reference.u32;
u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
th_value[row - 1][col - 2] = *(s32_t *)value;
log_d("th_set row=%d col=%d value = %d\r\n", row, col, *(s32_t *)value);
return SNMP_ERR_NOERROR;
}
/* 表列对象定义 */
static const struct snmp_table_col_def th_table_columns[] = {
{1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* thIndex */
{2, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* 温度 */
{3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* 湿度 */
{4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* 温度修正 */
{5, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* 湿度修正 */
};
/* 创建可读写表 */
static const struct snmp_table_node th_table = SNMP_TABLE_CREATE(1, th_table_columns, th_get_instance, th_get_next_instance, th_get_value, th_set_test, th_set_value);
static const struct snmp_node *const th_subnodes[] = {
&th_table.node.node,
};
const struct snmp_tree_node th_treenode = SNMP_CREATE_TREE_NODE(3, th_subnodes);
1.4 设备OID树创建
static const struct snmp_node *const mib2_nodes_dev[] =
{
&sysinfo_scalars.node.node,
&sensor_scalars.node.node,
&th_treenode.node,
};
static const struct snmp_tree_node snmp_mib2_root_dev = SNMP_CREATE_TREE_NODE(1, mib2_nodes_dev);
static const u32_t prvmib_base_oid[] = SNMP_DEVICE_OID;
const struct snmp_mib mib2_dev = SNMP_MIB_CREATE(prvmib_base_oid, &snmp_mib2_root_dev.node);
static const struct snmp_mib *dev_mibs[] = {&mib2, &mib2_dev};
1.5 完整实例代码
/**
* @file test_snmp.c
* @brief 基于 lwip-snmp 的测试程序
* @author
* @version 1.0
* @date
* @copyright Copyright (c) 2025
*/
#include "app.h"
#ifdef RT_LWIP_SNMP
#include "lwip/snmp.h"
#include "lwip/apps/snmp.h"
#include "lwip/apps/snmp_opts.h"
#include "lwip/apps/snmp_core.h"
#include "lwip/apps/snmp_mib2.h"
#include "lwip/apps/snmp_table.h"
#include "lwip/apps/snmp_scalar.h"
#include <string.h>
#define DBG_TAG "snmp"
#define DBG_LVL DBG_LOG
#include <rtdbg.h>
#define SNMP_ENTERPRISE_OID {1, 3, 6, 1, 4, 1, 5888}
#define SNMP_DEVICE_OID {1, 3, 6, 1, 4, 1, 5888, 1}
static u8_t sysdescr[30] = {"Hybrid Power"};
static u8_t syscontact[10] = {"FiberHome"};
static u8_t sysname[10] = {"FitON"};
static u8_t syslocation[10] = {"China"};
static u16_t ocstrlen_sysdescr = 0;
static u16_t ocstrlen_syscontact = 0;
static u16_t ocstrlen_sysname = 0;
static u16_t ocstrlen_syslocation = 0;
struct snmp_obj_id device_enterprise_oid = {
.len = 7,
.id = SNMP_ENTERPRISE_OID,
};
/*******************************************************************************
1.3.6.1.4.1.5888.1.1 系统信息-标量(只读字符串)
*******************************************************************************/
static char *identManufacturer = "FiberHome";
static char *identModel = "FitON DP48";
static char *identSN = "SN12345678";
static char *identSoftwareVersion = APP_SOFTWARE_VERSION;
static s16_t sysinfo_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
char *var = NULL;
s16_t var_len;
switch (node->oid)
{
case 1: /* identManufacturer 制造商 */
var = identManufacturer;
var_len = strlen(identManufacturer);
break;
case 2: /* identModel 产品型号 */
var = identModel;
var_len = strlen(identModel);
break;
case 3: /* identSN 产品SN号 */
var = identSN;
var_len = strlen(identSN);
break;
case 4: /* identSoftwareVersion 产品软件版本 */
var = identSoftwareVersion;
var_len = strlen(identSoftwareVersion);
break;
default:
LWIP_DEBUGF(SNMP_MIB_DEBUG, ("sysinfo_get_value(): unknown id: %"S32_F"\n", node->oid));
return 0;
}
LWIP_ASSERT("", (value != NULL));
MEMCPY(value, var, var_len);
return var_len;
}
static const struct snmp_scalar_array_node_def sysinfo_scalars_nodes[] = {
{1, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* 制造商 */
{2, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* 产品型号 */
{3, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* 产品SN号 */
{4, SNMP_ASN1_TYPE_OCTET_STRING, SNMP_NODE_INSTANCE_READ_ONLY}, /* 产品软件版本 */
};
/* 创建系统信息根节点 */
const struct snmp_scalar_array_node sysinfo_scalars = SNMP_SCALAR_CREATE_ARRAY_NODE(1, sysinfo_scalars_nodes, sysinfo_get_value, NULL, NULL);
/*******************************************************************************
1.3.6.1.4.1.5888.1.2 传感-标量(读写)
*******************************************************************************/
static u32_t sensor_value[4];
/* 获取值 */
static s16_t sensor_get_value(const struct snmp_scalar_array_node_def *node, void *value)
{
/* node->oid 当前节点OID值 */
if (node->oid < 3)
sensor_value[node->oid - 1] = node->oid * 100 + rand() % 10;
*(u32_t *)value = sensor_value[node->oid - 1];
return 4;
}
/* 设置检测 */
static snmp_err_t sensor_set_test(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
s32_t *sint_ptr = (s32_t *)value;
/* 值限制范围 */
if (*sint_ptr < 100 || *sint_ptr > 600)
return SNMP_ERR_WRONGVALUE;
return SNMP_ERR_NOERROR;
}
/* 设置值 */
static snmp_err_t sensor_set_value(const struct snmp_scalar_array_node_def *node, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
sensor_value[node->oid - 1] = *(s32_t *)value;
log_d("sensor_set oid = %d value = %d\r\n", node->oid, *(s32_t *)value);
return SNMP_ERR_NOERROR;
}
/* 标量节点定义 */
static const struct snmp_scalar_array_node_def sensor_scalars_nodes[] = {
{1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* Rsensor1 */
{2, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* Rsensor2 */
{3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* RWsensor1 */
{4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* RWsensor2 */
};
/* 创建传感标量组节点*/
const struct snmp_scalar_array_node sensor_scalars = SNMP_SCALAR_CREATE_ARRAY_NODE(2, sensor_scalars_nodes, sensor_get_value, sensor_set_test, sensor_set_value);
/*******************************************************************************
1.3.6.1.4.1.5888.1.2 温湿度-表(读写)
*******************************************************************************/
#define TH_SENSOR_NUM 4
static s32_t th_value[TH_SENSOR_NUM][4];
/* 表行大小区间 */
static const struct snmp_oid_range th_table_oid_ranges[] = {
{1, TH_SENSOR_NUM},
};
/* 获取当前实例 */
static snmp_err_t th_get_instance(const u32_t *column, const u32_t *row_oid, u8_t row_oid_len, struct snmp_node_instance *cell_instance)
{
LWIP_UNUSED_ARG(column);
/* check if incoming OID length and if values are in plausible range */
if (!snmp_oid_in_range(row_oid, row_oid_len, th_table_oid_ranges, LWIP_ARRAYSIZE(th_table_oid_ranges)))
return SNMP_ERR_NOSUCHINSTANCE;
cell_instance->reference.u32 = row_oid[0]; /* 传递行数 */
return SNMP_ERR_NOERROR;
}
/* 获取下一个OID实例 */
static snmp_err_t th_get_next_instance(const u32_t *column, struct snmp_obj_id *row_oid, struct snmp_node_instance *cell_instance)
{
u8_t i = 0;
struct snmp_next_oid_state state;
u32_t next_oid = 0;
/* 查找下个节点 */
snmp_next_oid_init(&state, row_oid->id, row_oid->len, &next_oid, 1);
for (i = 0; i < TH_SENSOR_NUM; i++)
{
u32_t test_oid = i + 1;
snmp_next_oid_check(&state, &test_oid, 1, NULL);
}
if (state.status == SNMP_NEXT_OID_STATUS_SUCCESS)
{
snmp_oid_assign(row_oid, state.next_oid, state.next_oid_len);
cell_instance->reference.u32 = *state.next_oid; /* 下个节点行OID */
return SNMP_ERR_NOERROR;
}
return SNMP_ERR_NOSUCHINSTANCE;
}
/* 获取值 */
static s16_t th_get_value(struct snmp_node_instance *instance, void *value)
{
u32_t row = instance->reference.u32;
u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
s32_t *value_s32 = (s32_t *)value;
/* 第一列索引 */
if (col == 1)
{
*value_s32 = row;
return sizeof(s32_t);
}
if (col < 4)
th_value[row - 1][col - 2] = row * 100 + col * 10 + rand() % 10 + th_value[row - 1][col];
*value_s32 = th_value[row - 1][col - 2];
return sizeof(s32_t);
}
/* 设置测试 */
static snmp_err_t th_set_test(struct snmp_node_instance *instance, u16_t len, void *value)
{
// u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
s32_t *sint_ptr = (s32_t *)value;
if (*sint_ptr < -600 || *sint_ptr > 600)
return SNMP_ERR_WRONGVALUE;
return SNMP_ERR_NOERROR;
}
/* 设置值 */
static snmp_err_t th_set_value(struct snmp_node_instance *instance, u16_t len, void *value)
{
LWIP_UNUSED_ARG(len);
u32_t row = instance->reference.u32;
u32_t col = SNMP_TABLE_GET_COLUMN_FROM_OID(instance->instance_oid.id);
th_value[row - 1][col - 2] = *(s32_t *)value;
log_d("th_set row=%d col=%d value = %d\r\n", row, col, *(s32_t *)value);
return SNMP_ERR_NOERROR;
}
/* 表列对象定义 */
static const struct snmp_table_col_def th_table_columns[] = {
{1, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* thIndex */
{2, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* 温度 */
{3, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_ONLY}, /* 湿度 */
{4, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* 温度修正 */
{5, SNMP_ASN1_TYPE_INTEGER, SNMP_NODE_INSTANCE_READ_WRITE}, /* 湿度修正 */
};
/* 创建可读写表 */
static const struct snmp_table_node th_table = SNMP_TABLE_CREATE(1, th_table_columns, th_get_instance, th_get_next_instance, th_get_value, th_set_test, th_set_value);
static const struct snmp_node *const th_subnodes[] = {
&th_table.node.node,
};
const struct snmp_tree_node th_treenode = SNMP_CREATE_TREE_NODE(3, th_subnodes);
/*******************************************************************************
1.3.6.1.4.1.5888.1.1 汇总设备OID树
*******************************************************************************/
static const struct snmp_node *const mib2_nodes_dev[] =
{
&sysinfo_scalars.node.node,
&sensor_scalars.node.node,
&th_treenode.node,
};
static const struct snmp_tree_node snmp_mib2_root_dev = SNMP_CREATE_TREE_NODE(1, mib2_nodes_dev);
static const u32_t prvmib_base_oid[] = SNMP_DEVICE_OID;
const struct snmp_mib mib2_dev = SNMP_MIB_CREATE(prvmib_base_oid, &snmp_mib2_root_dev.node);
static const struct snmp_mib *dev_mibs[] = {&mib2, &mib2_dev};
/*******************************************************************************
trap test
*******************************************************************************/
const ip_addr_t test_snmp_trap_ip = IPADDR4_INIT_BYTES(192, 168, 1, 200);
void cmd_snmp_test(int argc, char **argv)
{
struct snmp_varbind vb;
memset(&vb, 0, sizeof(struct snmp_varbind));
char *str = "trap test";
static const u32_t oid[] = {1, 3, 6, 1, 4, 1, 5888, 1, 5, 0};
snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
vb.type = SNMP_ASN1_TYPE_OCTET_STRING;
vb.value = (void *)str;
vb.value_len = strlen(str);
snmp_send_trap_specific(0, &vb);
// snmp_send_trap_generic(SNMP_GENTRAP_COLDSTART);
}
MSH_CMD_EXPORT_ALIAS(cmd_snmp_test, snmp, snmp agent test);
/**
* @brief snmp应用初始化
* @return int
*/
int app_snmp_init(void)
{
ocstrlen_sysdescr = (u16_t)strlen((char *)sysdescr);
ocstrlen_syscontact = (u16_t)strlen((char *)syscontact);
ocstrlen_sysname = (u16_t)strlen((char *)sysname);
ocstrlen_syslocation = (u16_t)strlen((char *)syslocation);
/* 修改mib2下的系统基础信息 */
snmp_mib2_set_sysdescr(sysdescr, &ocstrlen_sysdescr);
snmp_mib2_set_syscontact(syscontact, &ocstrlen_syscontact, 0);
snmp_mib2_set_sysname(sysname, &ocstrlen_sysname, 0);
snmp_mib2_set_syslocation(syslocation, &ocstrlen_syslocation, 0);
/* 设置企业OID */
snmp_set_device_enterprise_oid(&device_enterprise_oid);
snmp_set_auth_traps_enabled(SNMP_AUTH_TRAPS_DISABLED);
/* 设置trap目的地址 */
snmp_trap_dst_enable(0, 1);
snmp_trap_dst_ip_set(0, &test_snmp_trap_ip);
/* 设置mib、访问共同体 */
snmp_set_mibs(&dev_mibs[0], LWIP_ARRAYSIZE(dev_mibs));
snmp_set_community("public");
snmp_set_community_write("public");
/* 初始化snmp */
snmp_init();
return 0;
}
APP9_INIT_EXPORT(app_snmp_init);
#endif /* RT_LWIP_SNMP */
1.6 通信测试
使用 mibbrowser 工具测试

2 lwip-snmp 进阶使用
2.1 snmp_v3
snmp v3需mbedtls加密库支持,配置mbedtls软件包。
2.2 snmp trap

浙公网安备 33010602011771号