简单网络管理协议SNMP在嵌入式设备中的子代理实现
摘要:简单网络管理协议(SNMP:Simple Network Management Protocol)IETF定义的一套网络管理协议。利用SNMP,一个管理工作站可以远程管理所有支持这种协议的网络设备,包括监视网络状态、修改网络设备配置、接收网络事件警告等。当前物联网设备增长迅速,物联网设备总数已达到百亿数量级,由此网络设备的管理尤为重要。除了常规意义上的路由器、交换机和服务器等网络设备,还包括各行各业的嵌入式设备,这些设备也可以实现SNMP协议的支持,方便统一管理,本文主要以所在行业的嵌入式设备(后面简称设备)进行概述,以项目为背景,介绍了SNMP在设备中的子代理实现。
关键词:简单网络管理协议;管理工作站;嵌入式设备;子代理
案例背景
目前大多厂商设备没有统一的协议,各家都是自己的私有协议,涉及到多家厂商的设备和后端平台对接都需要进行协议对接,如果改变控制协议,开发难度大,且时间周期长,因此提出了一种迂回的解决方案,各家控制协议不变,只要提供SNMP协议支持即可。由于SNMP协议比较简单,已有多种开源版本实现,对于底层实现并不需要关注,只需要增加自己的业务逻辑即可。
负责的一个海外项目需要设备提供SNMP协议支持,实现设备受中心大平台的控制和管理,因此对于设备来说,只需要开发一个代理程序,作为中间人,实现后端平台与前端设备的交互。
系统框图
如图1所示,整个系统包括两大模块,管理站和代理,通过SNMP协议进行交互,SNMP协议属于应用层协议,传输层采用UDP协议。管理站可以对代理进行Get/Set请求,即读写操作,代理进行Get/Set应答;代理还可以进行Trap告警,即主动推送。按C/S模型划分,管理站属于客户端,代理属于服务器。
图1 SNMP的典型应用场景框图
SNMP介绍
SNMP中被管理的对象组成了一个树形结构,每个对象都是一个节点,定义在MIB数据库中,典型的MIB树形结构如图2 所示。
图2 典型MIB树形结构
SNMP访问一个被管对象都是通过对象命名树上的节点去访问,也就是说,如果你要定义一个被管对象,那么你就必须要在对象命名树上为它创建一个节点。一般对于企业开发而言,大都会在.1.3.6.1.4.1{iso(1) org(3) dod(6) internet(1) private(4) enterprises(1)}这个节点下重新创建新的节点给被管对象使用。
设备中SNMP子代理实现
SNMP目前的实现版本较多,主流的有C语言版本的Net-SNMP,C++版本的SNMP++,Java版本的jSNMP和Python版本的PySNMP。项目中采用了更为普遍的Net-SNMP,将源码下载进行编译安装到设备系统中,默认的SNMP代理(SNMP主代理snmpd)即可使用,接下来就是考虑如何将设备的业务逻辑实现SNMP支持,即扩展代理,常用三种扩展代理方式:
- 将自定义的.c和.h文件放入到SNMP的源代码安装包的扩展目录内,编译net-snmp时将扩展模块一同集成到net-snmp的libnetsnmpmib.a中。
2. 将源文件和头文件编译成动态库,让net-snmp动态加载。
3. 将新的MIB编译成子代理的模式,它将依附主代理运行,达到附加新MIB的目的。
项目中选择了实现方式3,下面详细介绍操作流程:
1)将协议文档转换为MIB文件;
一般来讲,自定义的MIB文件中变量模式主要有两种,一种是简单变量(就是单独的一个变量,可直接进行赋值),另一种是基于表的形式,其实就是需要实现一个链表,以设备某命令节点(简单变量)为例,
-- 1.3.6.1.4.1.1618.3.2.2.1
XXXCommandFlashObjs OBJECT IDENTIFIER
::= { XXXCommandObjs 1 }
-- 1.3.6.1.4.1.1618.3.2.2.1.1
XXXCommandFlash OBJECT-TYPE
SYNTAX CommandFlash
ACCESS read-write
STATUS current
DESCRIPTION "The flash command."
::= { XXXCommandFlashObjs 1 }
2)利用snmp的工具mib2c将mib文件的变量转换为源文件.c和.h,将自己的业务代码在合适的位置加入即可;指令为:mib2c mib2c.scalar.conf [MIB模块名::节点变量名],以命令XXXCommandFlash为例,源文件中会自动生成两个函数,如下:
/** 初始化节点及注册回调处理函数*/
void init_XXXCommandFlash(void)
{
const oid XXXCommandFlash_oid[] = { 1,3,6,1,4,1,1618,3,2,2,1,1 };
DEBUGMSGTL(("XXXCommandFlash", "Initializing\n"));
netsnmp_register_scalar(netsnmp_create_handler_registration( "XXXCommandFlash",
handle_XXXCommandFlash,
XXXCommandFlash_oid,
OID_LENGTH(XXXCommandFlash_oid),
HANDLER_CAN_RWRITE ));
}
/** 节点处理函数,包括Get/Set处理*/
int handle_XXXCommandFlash(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
switch(reqinfo->mode) {
case MODE_GET:
//业务代码,调用设备SDK处理(Get前处理), Get
break;
case MODE_SET_RESERVE1: /*Check*/ break;
case MODE_SET_RESERVE2: break;
case MODE_SET_FREE: break;
case MODE_SET_ACTION: /*Set*/ break;
case MODE_SET_COMMIT:
//业务代码,调用设备SDK处理(Set后处理)
break;
case MODE_SET_UNDO: break;
}
3)同(2),将设备所有配置相关的节点进行初始化和注册节点处理回调函数,这里为了减少代码编写工作,可以使用C++模板,将普通变量抽象为一类模板,将表变量抽象为一类模板,最终完成初始化函数的编写:
void init_yyysnmp(YYY &yyy); //函数名必须为init_XXX,才能被snmp代理识别,yyy为设备句柄
上面描述的都是Get/Set节点的处理,对于Trap节点直接调用Net-SNMP提供的API即可。
4)子代理main函数编写,示例如下:
static int keep_running = 1;
int main (int argc, char **argv)
{
SdkInit("127.0.0.1", PLATFORM); //设备 SDK初始化
std::string ip = "127.0.0.1";
YYY yyy(ip);
yyy.Login("password"); //登录设备
snmp_enable_filelog("/syslog/snmpd.log", 1); //初始化snmp日志文件
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,NETSNMP_DS_AGENT_ROLE, 1); //配置NET-SNMP为子代理模式
//SOCK_STARTUP; //初始化TCPIP,Windows需要
init_agent("yyysnmp"); //初始化代理库
init_yyysnmp(yyy); //新增mib初始化函数,步骤(3)所述
init_snmp("yyysnmp"); //读yyysnmp.conf配置文件
while(keep_running) {
agent_check_and_process(1); //blocking check and handle request
}
snmp_shutdown("yyysnmp"); //子代理关机
shutdown_agent();
yyy.Logout(); //注销设备
return 0;
}
5)编译子代理源码,生成子代理应用程序YYYsnmp;
6)snmpd.conf配置文件修改;
#################################################################
# Subagent control
# The agent can support subagents using a number of extension mechanisms.
# From the 4.2.1 release, AgentX support is being compiled in by default.
#
master agentx //开启子代理
rocommunity public //只读类型变量的访问社区为public
rwcommunity private //读写类型变量的访问社区为private
#################################################################
7)启动程序;包括设备主控mainControl,snmp主代理snmpd程序,snmp子代理YYYsnmp。
综上,设备中便实现了支持SNMP协议的子代理应用程序,后端大平台便可以使用SNMP对前端设备进行监控和控制,整个系统的框图为:
图3 基于SNMP协议的系统实现
如图3所示,后端管理平台作为网络管理工作站,通过SNMP协议对前端设备进行管理。后端平台通过SNMP协议与主代理进行通信,包括Get/Set消息,由主代理通过AgentX扩展协议将消息转发给子代理进行处理,子代理通过SDK与设备应用进行通信,对于trap告警消息直接由子代理上传给后端平台。关于SNMP,snmpd和AgentX的底层实现我们并不需要关注,直接将snmpd移植过来即可,我们关注的是根据子代理开发流程(上文介绍)将我们的业务代码编译为子代理即可。
之所以选用子代理方式进行开发,是因为AgentX协议是实现SNMP分布式扩展的通信协议,根据业务的扩展,会涉及到不断添加新的MIB,这样对于新增的MIB我们可以单独编译成一个新的子代理,形成一主多从(一个主代理master,多个子代理sub-agent)的架构,即分布式监控架构,这样就实现了动态扩展代理的需求,分布式架构如图4所示。
图4 基于SNMP子代理的分布式管理系统
总结
本案例主要给出了嵌入式设备的SNMP子代理实现方式,其它嵌入式设备完全可以复用实现流程,这样就可以实现不同厂商、支持不同协议的嵌入式设备可被后端平台统一进行管理,这也是分布式系统的一种简单实现方式。
参考文献
[1] 深入理解Net-SNMP[M], 张春强, 机械工业出版社.
[2] http://www.net-snmp.org/ Net-SNMP官方网站