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

posted @ 2025-06-19 17:33  silencehuan  阅读(215)  评论(0)    收藏  举报