第十五章 W55MH32 SNMP示例

目录

1 SNMP协议简介

2 SNMP协议特点

3 应用场景

4 使用MIB Browser管理W55MH32流程

5 SNMP架构组成

6 OID详解

7 SNMP报文格式

8 实现过程

9 运行结果

10 总结


本篇文章,我们将详细介绍如何在W55MH32芯片上面实现SNMP功能。并通过实战例程,为大家讲解如何使用MIB Browser管理W55MH32。

该例程用到的其他网络协议,例如DHCP,请参考相关章节。有关 W55MH32 的初始化过程,请参考 Network Install 章节,这里将不再赘述。

1 SNMP协议简介

SNMP(Simple Network Management Protocol,简单网络管理协议)是一种用于管理和监控网络设备的协议。它是应用层协议,广泛应用于网络设备(如路由器、交换机、服务器、打印机等)的管理和监控。SNMP提供了机制以便网络管理员可以监控网络性能、发现网络问题,并对设备进行管理。

2 SNMP协议特点

简单性:设计轻量,便于实现和部署。

互操作性:提供标准化的设备管理方式,不同厂商的设备可以通过SNMP实现互通。

跨平台支持:SNMP是一种开放的标准协议,被广泛应用于各种网络设备和操作系统。

实时监控:支持快速的数据采集和报警机制。

扩展性:通过MIB支持不同设备的特定功能。

资源效率:协议设计轻量,适合低带宽和高延迟的网络环境。

3 应用场景

接下来,我们了解下在W55MH32上,可以使用SNMP协议完成哪些操作及应用呢?

故障报警和日志管理:设备在检测到异常或故障时,可以通过 SNMP TRAP 将报警信息发送到网络管理系统。

工业自动化和环境监控:在工业自动化和环境监控中,W55MH32 可通过 SNMP 汇报传感器数据。

数据中心和机房管理:用于数据中心和机房中监控服务器、交换机及其他网络设备的状态。

4 使用MIB Browser管理W55MH32流程

  1. 下载并安装MIB Browser(链接:https://www.ireasoning.com/download/mibfree/setup.exe)
  2. 创建分支

打开安装目录下 mibs 文件夹,找到 RFC1213-MIB 文件,右键使用记事本打开,上方路径栏可以寻找路径。

在snmp后添加一个新分支,命名为User

  1. 添加叶子节点(功能)

在分支后方继续添加功能代码

叶子节点格式如下:

setLED OBJECT-TYPE  添加一个新叶子节点,命名为 setLED

SYNTAX  INTEGER { enabled(1),disabled(0) } 设置数据类型

ACCESS  read-write 设置读写权限

DESCRIPTION 注释

::= { User 1 } 叶子所在分支,与叶子编号

添加完毕后保存并退出

添加完成后,MIB Browser软件如下所示:

  1. 代码适配功能
  2. 测试

5 SNMP架构组成

SNMP架构包括以下三个主要部分:

管理站(Manager):运行SNMP管理软件,用于发送请求和接收设备信息。通过命令操作网络设备,执行配置或监控任务。

代理(Agent):安装在受管理设备上的软件,负责将设备的状态信息存储在MIB中,并响应来自管理站的查询。能动地发送陷阱(Trap)以报告事件。

管理信息库(MIB):定义设备的可管理参数及其数据结构MIB通常以树状结构组织,每个节点代表一个管理对象,具有唯一的对象标识符(OID)。

协议(SNMP协议本身):负责管理站和代理之间的通信,支持基本操作如获取、设置和通知。

6 OID详解

简单网络管理协议(SNMP)的OID(对象标识符)是一个用于唯一标识网络设备上管理信息库(MIB)中对象的标识符。OID是一种分层的命名方案,允许管理员查询和设置网络设备上的各种参数。

下面是OID的详解:

OID结构

OID由一系列整数组成,这些整数通过点号(.)分隔,形成了一个层次结构。例如:

1.3.6.1.2.1.1.1.0

在这个结构中,每个数字都代表一个组织或节点在层次结构中的位置。

OID层次解释

1:表示ISO(国际标准化组织)

3:表示org(组织)

6:指定IETF(互联网工程任务组)作为组织

1:表示IETF管理的MIB(管理信息库)

后续的数字则进一步定义了特定的MIB模块、对象类型、实例等信息。

常见的OID前缀

1.3.6.1.2.1:这是最常用的OID前缀,通常简写为.iso.org.dod.internet.mgmt.mib-2,它指的是IETF定义的MIB-2

具体OID示例

1.3.6.1.2.1.1.1.0:这是sysDescrOID,用于获取系统描述。

1.3.6.1.2.1.1.2.0:这是sysObjectIDOID,用于获取系统对象标识符。

1.3.6.1.2.1.1.3.0:这是sysUpTimeOID,用于获取系统正常运行时间。

如何使用OID

查询:使用SNMP GET请求,可以查询特定OID的值。

设置:使用SNMP SET请求,可以修改特定OID的值(需要设备支持)。

遍历:使用SNMP WALK请求,可以遍历一个OID下的所有子节点。

注意事项

OID的具体值和结构可能会随着网络设备的不同而有所不同。在使用OID之前,最好查阅相应设备的MIB文档,以了解其支持的具体OID及其功能。OIDSNMP管理中不可或缺的部分,通过OID,网络管理员可以进行监控网络状态、配置网络设备、接收警报通知等操作。理解和掌握OID对于网络管理和故障排除非常重要。

7 SNMP报文格式

SNMP 报文基于ASN.1Abstract Syntax Notation One)编码规则,通常使用BERBasic Encoding Rules)进行传输。以下是SNMP报文的基本格式和关键字段,本例程中使用的是SNMPv1版本,以下对SNMPv1进行讲解,而对于其他版本的报文格式,由于篇幅有限,这里将不再进行讲解,感兴趣的朋友可自行查阅资料进行学习。

SNMP报文结构

字段名称

类型

描述

Message

序列(Sequence)

整个 SNMP 消息的容器,包含以下字段。

Version

整数(Integer)

SNMP 协议版本号,0 表示 SNMPv1。

Community

字符串(Octet String)

社区字符串,用于身份验证,如 public 或 private。

PDU 类型

标记(Tag, Context-Specific)

表示操作类型,如:GET(0xA0)、GET-NEXT(0xA1)、SET(0xA3)、TRAP(0xA4)。

Request ID

整数(Integer)

请求的唯一标识,用于匹配请求和响应。

Error Status

整数(Integer)

错误状态,取值范围为:0(noError)、1(tooBig)、2(noSuchName)等。

Error Index

整数(Integer)

错误索引,指示变量绑定列表中出错的变量位置(从 1 开始计数)。

Variable Bindings

序列(Sequence of VarBinds)

变量绑定列表,每个绑定包含一个 OID 和对应的值。

- OID

对象标识符(OID)

被管理对象的标识符,如 1.3.6.1.2.1.1.1.0 表示系统描述(sysDescr)。

- Value

可变类型(Null, Integer, String 等)

OID 对应的值,可能为空值(GET 请求)或具体数据(响应或 SET 请求)。

报文字段详解

1. Message(消息整体)

这是 SNMP 消息的最外层结构,是一个序列(Sequence),包含以下三个部分:

  • Version(版本号)
    此字段定义 SNMP 协议的版本号,用一个整数表示:
    • 0 表示 SNMPv1。
    • 1 表示 SNMPv2c。
    • 3 表示 SNMPv3。
      该字段是解析报文的基础,不同版本的报文格式存在差异。
  • Community(社区字符串)
    社区字符串是 SNMPv1 和 SNMPv2c 的一种简单身份验证机制,用于限制对管理对象的访问权限。它是一个字符串(Octet String),常见的值包括:
    • public:表示只读访问权限。
    • private:表示读写访问权限。
  • PDU(协议数据单元)类型
    PDU 定义了操作类型,通过一个标记值(Tag, Context-Specific)来区分:
    • 0xA0:GET 请求,用于获取管理对象的值。
    • 0xA1:GET-NEXT 请求,用于获取下一个对象的值。
    • 0xA3:SET 请求,用于设置管理对象的值。
    • 0xA4:TRAP,用于代理向管理站报告事件。

2. Request ID(请求 ID

请求 ID 是一个整数,用于唯一标识一个请求。它由发起方生成,并在响应中携带相同的 ID。通过此字段,接收方可以将响应与对应的请求进行匹配。如果响应中的请求 ID 不一致,则表明响应与请求无关。

3. Error Status(错误状态)

此字段用整数表示请求的执行状态:

  • 0:noError,表示请求执行成功,没有错误。
  • 1:tooBig,请求的响应数据超出接收方的最大允许大小。
  • 2:noSuchName,请求中指定的 OID 不存在。
  • 3:badValue,请求中的值非法或不支持。
  • 4:readOnly,请求试图修改只读对象。
  • 5:genErr,发生了通用错误,具体原因未明确。

4. Error Index(错误索引)

如果 Error Status 的值不为 0,此字段指示变量绑定列表中出错的变量位置(从 1 开始计数)。如果没有错误,此字段的值为 0。

5. Variable Bindings(变量绑定列表)

变量绑定列表是 SNMP 报文的核心部分,包含一个或多个变量绑定(VarBind)。每个变量绑定由以下两部分组成:

  • OID(对象标识符)
    OID 是管理对象的唯一标识符,用点分十进制表示。例如:
    • 1.3.6.1.2.1.1.1.0:表示 sysDescr,系统描述。
    • 1.3.6.1.2.1.1.5.0:表示 sysName,系统名称。
  • Value(值)
    OID 的值根据请求类型不同可能为以下几种:
    • 在 GET 请求中,值通常为空(Null)。
    • 在 GET-RESPONSE 报文中,值为具体数据,例如整型(Integer32)、字符串(Octet String)等。
    • 在 SET 请求中,值是要设置的新值。

SNMP报文解析

MIB Browser向W55MH32发送LED设置报文:

|报文解析|

Simple Network Management Protocol           (简单网络管理协议(SNMP 报文))

    version: version-1 (0)                   (使用的 SNMP 协议版本,值为 0 表示 SNMPv1)

    community: public                        (社区字符串为 "public",通常表示只读权限)

    data: set-request (3)                    (PDU 类型为 SET-REQUEST,表示设置管理对象的值)

        set-request

            request-id: 1479407980            (请求的唯一标识符,用于匹配请求和响应)

            error-status: noError (0)         (错误状态为 noError (0),表示没有错误发生)

            error-index: 0                   (错误索引为 0,表示变量绑定列表中没有错误对象)

            variable-bindings: 1 item         (变量绑定列表中包含 1 个变量)

                1.3.6.1.2.1.12.1.0: 1         (OID 1.3.6.1.2.1.12.1.0,设置的值为 1)

                    Object Name: 1.3.6.1.2.1.12.1.0 (iso.3.6.1.2.1.12.1.0)        (OID 对应的完整名称)

                    Value (Integer32): 1       (设置的值为整数类型,值为 1)

    [Response In: 237]                       (表示该请求的响应报文序号为 237)

|报文原文|

30 2a 02 01 00 04 06 70 75 62 6c 69 63 a3 1d 02 04 58 2d f9 6c 02 01 00 02 01 00 30 0f 30 0d 06 08 2b 06 01 02 01 0c 01 00 02 01 01

W55MH32响应报文:

|报文解析|

Simple Network Management Protocol

    version: version-1 (0)                   (版本号:SNMPv1(值为 0))

    community: public                        (社区字符串:"public",用于身份验证)

    data: get-response (2)                   (数据类型:GET-RESPONSE(值为 2),表示这是一个响应报文)

        get-response                         (GET-RESPONSE 数据部分)

            request-id: 1479407980            (请求 ID1479407980,用于匹配请求和响应)

            error-status: noError (0)         (错误状态:noError(值为 0),表示没有错误)

            error-index: 0                   (错误索引:0,表示没有发生错误的变量索引)

            variable-bindings: 1 item         (变量绑定:包含 1 个变量)

                1.3.6.1.2.1.12.1.0: 1         (变量绑定内容)

                    Object Name: 1.3.6.1.2.1.12.1.0 (iso.3.6.1.2.1.12.1.0)        (对象标识符(OID))

                    Value (Integer32): 1       (OID 对应的值,类型为 Integer32,值为 1)

    [Response To: 236]                       (对请求 ID 236 的响应)

    [Time: 0.023844000 seconds]              响应耗时:0.023844 )

|报文原文|

30 2a 02 01 00 04 06 70 75 62 6c 69 63 a2 1d 02 04 58 2d f9 6c 02 01 00 02 01 00 30 0f 30 0d 06 08 2b 06 01 02 01 0c 01 00 02 01 01

8 实现过程

接下来,我们看看如何在代码上适配MIB Browser上添加的功能。

注意:测试实例需要PC端和W55MH32处于同一网段。

步骤1:初始化LED并注册到SNMP

user_led_init();
user_led_control_init(get_user_led_status, set_user_led_status);

步骤2:注册snmp定时器

/**
 * @brief   1ms timer IRQ Handler
 * @param   none
 * @return  none
 */
void TIM3_IRQHandler(void)
{
    static uint32_t tim3_1ms_count = 0;
    static uint8_t tim3_10ms_count = 0;
    if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET)
    {
        tim3_1ms_count++;
        tim3_10ms_count++;
        if (tim3_1ms_count >= 1000)
        {
            DHCP_time_handler();
            
            tim3_1ms_count = 0;
        }
        if(tim3_10ms_count>=10)
        {
            SNMP_time_handler();
            tim3_10ms_count=0;
        }
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
    }
}

我们需要10ms调用一次SNMP_time_handler()函数,方便SNMP进行超时处理。

步骤3:添加功能函数

在snmp_custom.c文件中的snmpData结构体变量中,添加功能函数:

dataEntryType snmpData[] =
{
    // System MIB
    // SysDescr Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 1, 0}, SNMPDTYPE_OCTET_STRING,   30,               {"WIZnet Embedded SNMP Agent"},                  NULL,                  NULL},

    // SysObjectID Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 2, 0},       SNMPDTYPE_OBJ_ID,    8,         {"\x2b\x06\x01\x02\x01\x01\x02\x00"},                  NULL,                  NULL},

    // SysUptime Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 3, 0},   SNMPDTYPE_TIME_TICKS,    0,                                         {""},         currentUptime,                  NULL},

    // sysContact Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 4, 0}, SNMPDTYPE_OCTET_STRING,   30,             {"http://www.wizwiki.net/forum"},                  NULL,                  NULL},

    // sysName Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 5, 0}, SNMPDTYPE_OCTET_STRING,   30,                  {"http://www.wiznet.co.kr"},                  NULL,                  NULL},

    // Location Entry
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 6, 0}, SNMPDTYPE_OCTET_STRING,   30,                         {"4F Humax Village"},                  NULL,                  NULL},

    // SysServices
    {   8,                                  {0x2b, 6, 1, 2, 1, 1, 7, 0},      SNMPDTYPE_INTEGER,    4,                                         {""},                  NULL,                  NULL},

    {   8,                                  {0x2b, 6, 1, 2, 1, 12, 2, 0}, SNMPDTYPE_OCTET_STRING,   30,                                         {""}, get_LEDStatus_UserLED,                  NULL},

    {   8,                                  {0x2b, 6, 1, 2, 1, 12, 1, 0},      SNMPDTYPE_INTEGER,    4,                                         {""},                  NULL, set_LEDStatus_UserLED},

    // OID Test #1 (long-length OID example, 19865)
    {0x0a, {0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x9b, 0x19, 0x01, 0x00}, SNMPDTYPE_OCTET_STRING,   30,                  {"long-length OID Test #1"},                  NULL,                  NULL},

    // OID Test #2 (long-length OID example, 22210)
    {0x0a, {0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xad, 0x42, 0x01, 0x00}, SNMPDTYPE_OCTET_STRING,   35,                  {"long-length OID Test #2"},                  NULL,                  NULL},

    // OID Test #2: SysObjectID Entry
    {0x0a, {0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0xad, 0x42, 0x02, 0x00},       SNMPDTYPE_OBJ_ID, 0x0a, {"\x2b\x06\x01\x04\x01\x81\xad\x42\x02\x00"},                  NULL,                  NULL},
};

结构体变量snmpData 的结构体dataEntryType定义如下所示:

typedef struct {
    uint8_t oidlen;
    uint8_t oid[MAX_OID];
    uint8_t dataType;
    uint8_t dataLen;
    union {
        uint8_t octetstring[MAX_STRING];
        uint32_t intval;
    } u;
    void (*getfunction)(void *, uint8_t *);
    void (*setfunction)(int32_t);
} dataEntryType;

步骤4:初始化snmp协议

void snmpd_init(uint8_t * managerIP, uint8_t * agentIP, uint8_t sn_agent, uint8_t sn_trap)
{
#ifdef _SNMP_DEBUG_
    printf("\r\n - SNMP : Start SNMP Agent Daemon\r\n");
#endif
    SOCK_SNMP_AGENT = sn_agent;
    SOCK_SNMP_TRAP = sn_trap;

    if((SOCK_SNMP_AGENT > _WIZCHIP_SOCK_NUM_) || (SOCK_SNMP_TRAP > _WIZCHIP_SOCK_NUM_)) return;

    startTime = getSNMPTimeTick(); // Start time (unit: 10ms)
    initTable(); // Settings for OID entry values
    
    initial_Trap(managerIP, agentIP);

/*
    // Example Codes for SNMP Trap
    {
              dataEntryType enterprise_oid = {0x0a, {0x2b, 0x06, 0x01, 0x04, 0x01, 0x81, 0x9b, 0x19, 0x01, 0x00},
                                                                                             SNMPDTYPE_OBJ_ID, 0x0a, {"\x2b\x06\x01\x04\x01\x81\x9b\x19\x10\x00"},          NULL, NULL};

              dataEntryType trap_oid1 = {8, {0x2b, 6, 1, 4, 1, 0, 11, 0}, SNMPDTYPE_OCTET_STRING, 30, {""}, NULL, NULL};
              dataEntryType trap_oid2 = {8, {0x2b, 6, 1, 4, 1, 0, 12, 0}, SNMPDTYPE_INTEGER, 4, {""}, NULL, NULL};

              strcpy((char *)trap_oid1.u.octetstring, "Alert!!!");       // String added
              trap_oid2.u.intval = 123456; // Integer value added

              // Generic Trap: warmStart
              snmp_sendTrap((void *)"192.168.0.214", (void *)"192.168.0.112", (void *)"public", enterprise_oid, SNMPTRAP_WARMSTART, 0, 0);

              // Enterprise-Specific Trap
              snmp_sendTrap((void *)"192.168.0.214", (void *)"192.168.0.112", (void *)"public", enterprise_oid, 6, 0, 2, &trap_oid1, &trap_oid2);
        }
*/
}

这一步,主要是将使用的socket号,管理IP地址,请求IP地址等参数注册进去,并且记录开始时间。如果想使用Trap主动上报,可以参考注释中的示例代码。

步骤5:在主循环中运行snmpd_run()函数

snmpd run()函数代码如下:

int32_t snmpd_run(void)
{
    int32_t ret;
    int32_t len = 0;
    
    uint8_t svr_addr[6];
    uint16_t  svr_port;

    if(SOCK_SNMP_AGENT > _WIZCHIP_SOCK_NUM_) return -99;
    
    switch(getSn_SR(SOCK_SNMP_AGENT))
    {
        case SOCK_UDP :
            if ( (len = getSn_RX_RSR(SOCK_SNMP_AGENT)) > 0)
            {
                request_msg.len= recvfrom(SOCK_SNMP_AGENT, request_msg.buffer, len, svr_addr, &svr_port);
            }
            else
            {
                request_msg.len = 0;
            }

            if (request_msg.len > 0)
            {
#ifdef _SNMP_DEBUG_
                dumpCode((void *)"\r\n[Request]\r\n", (void *)"\r\n", request_msg.buffer, request_msg.len);
#endif
                // Initialize
                request_msg.index = 0;
                response_msg.index = 0;
                errorStatus = errorIndex = 0;
                memset(response_msg.buffer, 0x00, MAX_SNMPMSG_LEN);

                // Received message parsing and send response process
                if (parseSNMPMessage() != -1)
                {
                    sendto(SOCK_SNMP_AGENT, response_msg.buffer, response_msg.index, svr_addr, svr_port);
                }

#ifdef _SNMP_DEBUG_
                dumpCode((void *)"\r\n[Response]\r\n", (void *)"\r\n", response_msg.buffer, response_msg.index);
#endif
            }
            break;

        case SOCK_CLOSED :
            if((ret = socket(SOCK_SNMP_AGENT, Sn_MR_UDP, PORT_SNMP_AGENT, 0x00)) != SOCK_SNMP_AGENT)
                return ret;
#ifdef _SNMP_DEBUG_
            printf(" - [%d] UDP Socket for SNMP Agent, port [%d]\r\n", SOCK_SNMP_AGENT, PORT_SNMP_AGENT);
#endif
            break;

        default :
            break;
    }


    return 1;
}

snmpd_run()函数会执行一个UDP状态机,当收到SNMP管理的消息后会执行解析以及回复操作。

9 运行结果

烧录例程运行后,首先可以看到打印了PHY链路检测和DHCP获取网络信息,然后是运行SNMP程序:

打开MIB Borwser,输入W55MH32的地址,然后依次点击system分支下的各个节点,获取到的结果与代码定义相同:

再找到User分支下的setLED 指令,右键指令,点击 set,类型选择 integerValue 1,点击 OK

getLED 指令,右键指令,点击 get,即可读出 LED 状态:

10 总结

本文讲解了如何在 W55MH32 芯片上实现 SNMP 功能,通过实战例程展示了使用 MIB Browser 管理 W55MH32 的具体过程,涵盖在 MIB Browser 中创建分支、添加叶子节点,以及在代码中适配功能等关键步骤。文章详细介绍了 SNMP 协议的概念、特点、应用场景、架构组成、OID 详解和报文格式,帮助读者理解其在网络设备管理和监控中的重要作用。

下一篇文章将聚焦 PING 命令,解析其测试网络连通性的原理及在网络故障排查中的应用,同时讲解如何在W55MH32上使用 PING 命令进行网络诊断,敬请期待!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值