NET-SNMP开发实践
[从兴公司 - 王祖祥 浏览该作者其他文章]   点击:36
 
【摘 要】最近项目中需要用SNMP实现对APACHE http server的监控,由于项目后台开发使用C语言,故选择使用NET-SNMP包来实现对SNMP的开发与实现。对于NET-SNMP本人才刚入门,总会碰到N多的问题,网上对于NET-SNMP的资料就更少了,特别是缺少NET-SNMP的所涉及的整个开发过程。所以就有了一个冲动就是把学习中的过程写下来。本文将从NET-SNMP的安装配置、SNMP get、set、trap等主要三个用例的实现来描述使用NET-SNMP开发的全过程。
 
【关键字】SNMP、MIB、ASN1、OID
 
【系统环境】由于移植及运行环境等原因,本文的程序代码及命令的使用环境及版本如下:
OS: SunOS solaris 5.9 Generic_112234-12 i86pc i386 i86pc
Perl: This is perl, v5.6.1 built for i86pc-solaris-64int
Net-snmp: Version:  5.4.1
GCC:Reading specs from /usr/local/lib/gcc/i386-pc-solaris2.9/3.4.1/specs gcc version 3.4.1
 
1 NET-SNMP基本介绍
 
为了节约篇幅,关于SNMP(简单网络管理协议)的相关内容这里就不用介绍了。
 
目前关于SNMP的开发包主要有NET-SNMP(for C)、SNMP++(for C++)、SNMP4J(snmp++的JAVA版本)、SNMPJ(NET-SNMP的JAVA版本)。NET-SNMP的早期版本(5.X以前)叫ucd-snmp,源自于卡耐基·梅隆大学的SNMP软件包CMU snmp 2.1.2.1,由加州大学Davis分校(University of California at Davis)开发与维护,后来由SourceForge ( [url]www.sourceforge.net[/url])开发维护管理, 并更名为net-snmp(5.X及以后版本),其最新版本为5.4.1。
 
NET-SNMP的主要内容包括:
· 完整的API用于SNMP(支持V1、V2、V3版本)应用开发(包括c、perl、Python等的API)
· 一个可扩展的SNMP代理程序(snmpd);开发员可以扩展自己的代理程序
· 一套工具命令集(snmpget、snmpset、snmptrap、snmpwalk、snmp等)
· 一个trap接收进程,用于接收和显示trap。并可以将trap记录到日志文件里
· 一个图形化的MIB浏览工具(tkmib:基于Tk/Perl的)
 
 
2 NET-SNMP的安装、配置
 
2.1 NET-SNMP的安装
 
NET-SNMP包目前可以移植的版本包括各种UNIX(基于SYSTEM V内核及基于BSD内核)、LINUX、WINX版本。
 
目前NET-SNMP包的安装主要有程序编译安装与二进制文件安装两种方式,源程序安装可以从NET-SNMP的官网下载然后按照常规的configure, make ,make install三个步骤就可成功编译安装。其相关的二进制安装可以到其官网及各OS厂商的网站下载。
 
FOR SOLARIS 9的安装请到SUN的官网下载:
gcc-3.4.1-sol9-intel-local.gz、libgcc-3.4.1-sol9-intel-local.gz、
netsnmp-5.4.1-sol9-x86-local.gz、openssl-0.9.8h-sol9-x86-local.gz。
 
其遵循的安装过程为:
·gzip –d xxx.gz (解压缩)
·tar –xvf *.tar (如果有打包文件,请解包)
·pkgadd –d ./xxxx(安装)
安装完毕后,请在/etc/profile中设置好BIN的PATH路径。
 
2.2 NET-SNMP的配置
 
2.2.1 snmpconf 配置
 
我们使用/usr/local/bin/ snmpconf,其由perl编写,所以在运行前,请确认您的PERL安装路径,并更改snmpconf的第1行PERL脚本BIN路径。Snmpconf脚本主要用来配置snmpd.conf、snmptrapd.conf。snmpconf运行后是一个可以交互的配置设置过程,主要设置:
·System information setup ——包括位置、联系人信息等。
·Access control setup —— community name、
·Agent Operating Mode ——AGENT IP、PORT等。
 
设置完毕后,用户可以自己修改snmpd.conf文件中的参数信息。
 
2.2.2 启动snmpd
 
使用NET-SNMP的snmpd可扩展的代理进程替换OS的snmpd。
 
为了方便系统启动时,自动运行net-snmp代理程序,生成/etc/rc3.d/ S78net-snmp shell文件(solaris的多用户运行等级为3):S78net-snmp 此SHELL脚本请参考 S78net-snmp。
屏蔽原来OS的SNMPD的配置文件/etc/rc3.d/ S76snmpdx及S77dmi文件。
启动NET-SNMP的代理程序:./ S78net-snmp start。
停止NET-SNMP的代理程序:./ S78net-snmp stop。
 
2.2.3 测试NET-SNMP snmpd
 
# snmpget -v 1 -c public localhost sysDescr.0
SNMPv2-MIB::sysDescr.0 = STRING: SunOS solaris 5.9 Generic_112234-12 i86pc
# snmpget -v 1 -c public localhost sysLocation.0
SNMPv2-MIB::sysLocation.0 = STRING: wangzuxiang
至此NET-SNMP的安装、配置完成。
 
3 NET-SNMP的开发
 
3.1 SNMP GET开发
 
获取MIB中OID对象值(snmpget操作)的开发非常简单,其大致的过程为:
· 初始化一个SNMP会话;
· 定义会话属性;
· 增加一个MIB到当前的MIB目录树中(可选项);
· 创建一个PDU包 (Primary Data Unit) ;
· 设置OID(或多个)到PDU中;
· 发送请求并等待响应;
· 根据响应值处理业务数据;
· 释放PDU资源;
· 关闭会话。
 
mydemo.c范例为获取MIB表sysDescr对象(该对象表示设备的描述信息)、sysName、sysLocation等对象值,也可以使用snmptranslate -On将其名称转换为OID。例如:
% snmptranslate .1.3.6.1.2.1.1.3.0(转换OID名称)
         SNMPv2-MIB::sysUpTime.0
% snmptranslate -On SNMPv2-MIB::sysUpTime.0(转换OID)
         .1.3.6.1.2.1.1.3.0
    % snmptranslate -Tp -IR system(显示MIB树结构)
+--system(1)
      |
      +-- -R-- String    sysDescr(1)
      |        Textual Convention: DisplayString
      +-- -R-- ObjID     sysObjectID(2)
      +-- -R-- TimeTicks sysUpTime(3)
      +-- -RW- String    sysContact(4)
编译mydemo.c:
Gcc –o mydemo mydemo.c -lsnmp
运行mydemo:
./mydemo
SNMPv2-MIB::sysDescr.0 = STRING: SunOS solaris 5.9 Generic_112234-12 i86pc
SNMPv2-MIB::sysName.0 = STRING: solaris
SNMPv2-MIB::sysLocation.0 = STRING: wangzuxiang
值 #1 是一个字符串: SunOS solaris 5.9 Generic_112234-12 i86pc
值 #2 是一个字符串: solaris
值 #3 是一个字符串: wangzuxiang
 
注意:在实际的开发过程中,如果轮询多个agent上的MIB OID对象时,可以使用异步的多路复用技术来实现。类似代码如下:
while (active_hosts) {/*轮询某个AGENT*/
    int fds = 0, block = 1;
    fd_set fdset;
    struct timeval timeout;
    FD_ZERO(&fdset);
    snmp_select_info(&fds, &fdset, &timeout, &block);
    fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout);
    if (fds < 0) {
        perror("select failed");
        exit(1);
    }
    if (fds)
        snmp_read(&fdset);
    else        snmp_timeout();
  }
 
3.2 SNMP agent开发
 
扩展Agent的开发,NET-SNMP提供了三种方式:
· 动态联编(此方法需要NET-SNMP的源程序)。
· 动态加载库。
· 子代理的方式。
 
接下来将重点描述动态加载库的方式,其他的方式我目前还没有去实验,大家可以参考其官网上的例子进行。下面的例子将在AGENT中实现,GET/SET的方法接口。
 
3.2.1 准备 MIB 文件
 
为了方便,我们使用的MIB还是官网上的 NET-SNMP-TUTORIAL-MIB.txt。
 
将NET-SNMP-TUTORIAL-MIB.txt拷贝到/usr/local/share/snmp/mibs。
修改/usr/local/share/snmp/snmp.conf,在最后一行增加:mibs +NET-SNMP-TUTORIAL-MIB
或者在SHELL环境变量中定义:export MIBS=+NET-SNMP-TUTORIAL-MIB。
否则在运行程序或做SNMP操作时,会出现MIB无法找到等错误现象。
 
3.2.2 编译动态库
 
NET-SNMP的usr/local/bin/mib2c工具能够将使用MIB2C工具程序把MIB库模块文件转换成C源代码。假设MIB库模块为modulename,执行mib2c modulename此时,MIB2C会在当前目录下生成两个C源文件:modulename.h 和modulename.c,这两个文件是根据所设计的MIB库模块转换而成的,也是需要加入到NET-SNMP软件包实现SNMP Agent功能扩展的源代码。注意,MIB2C为PERL脚本编写,为了让PERL支持SNMP,您需要下载PERL CPAN FOR SNMP的包。
 
Mib2c需要为-c操作指定一个配置文件,此配置文件感觉为预生成的模板文件,如果要写scalars则用mib2c.scalar.conf文件,如果要写Table则用mib2c.mfd.conf,如果带有TRAP则用mib2c.notify.conf。
 
%mib2c -c mib2c.scalar.conf  nstAgentPluginObject
 
MIB2C将生成的文件为 nstAgentPluginObject.c和 nstAgentPluginObject.h文件。
 
在nstAgentPluginObject.c文件中为实现SET/GET操作,可以在switch (reqinfo->mode)下的MODE_SET_COMMIT(SET操作)与MODE_GET(GET操作)实现。
 
编译成.so文件:
gcc –I. -c -o nstAgentPluginObject.o nstAgentPluginObject.c
gcc -g -fPIC -shared -o nstAgentPluginObject.so nstAgentPluginObject.o(编译成SO库)
 
3.2.3 加载动态库
 
Net-snmp的snmpd加载动态库以实现agent的扩展有2种加载方式:
 
(1)不停止SNMPD进程的情况下加载。
UCD-DLMOD-MIB.txt定义了MIB条目的模块名,动态库路径及状态。使用此方法可以在不重起代理的情况下配置各动态模块加载与卸载。
其详细的MIB定义:cat /usr/local/share/snmp/mibs/UCD*DLMOD*.txt。
 
· 查看哪些.so被加载
#snmpget -v 1 -c public localhost UCD-DLMOD-MIB::dlmodStatus.1
 
· 尝试获取某个MIB的OID值
#Snmpget-v2c -c public localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0
NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0 = No Such Object available on this agent at this OID(其表示没有找到)
 
· UCD-DLMOD-MIB表中创建一个模块实例
#snmpset -v 1 -c private localhost UCD-DLMOD-MIB::dlmodStatus.1 i create
       UCD-DLMOD-MIB::dlmodStatus.1 = INTEGER: create(6)
 
· 获取dlmodStatus值
#snmpget -v 1 -c public localhost UCD-DLMOD-MIB::dlmodStatus.1
UCD-DLMOD-MIB::dlmodStatus.1 = INTEGER: unloaded(2)
说明模块实例已经存在,但没有被加载
 
· 设置需装载模块的名称及路径
#snmpset -v 1 -c private localhost UCD-DLMOD-MIB::dlmodName.1 s \ "nstAgentPluginObject" UCD-DLMOD-MIB::dlmodPath.1 s "/oracle/agent/plugin/nstAgentPluginObject.so"
       UCD-DLMOD-MIB::dlmodName.1 = STRING: nstAgentPluginObject
UCD-DLMOD-MIB::dlmodPath.1 = STRING: /oracle/agent/plugin/nstAgentPluginObject.so
 
· 装载模块
# snmpset -v 1 -c private localhost UCD-DLMOD-MIB::dlmodStatus.1 i load
UCD-DLMOD-MIB::dlmodStatus.1 = INTEGER: load(4)
 
· 确认模块被加载
#snmpget -v 1 -c public localhost UCD-DLMOD-MIB::dlmodStatus.1
UCD-DLMOD-MIB::dlmodStatus.1 = INTEGER: loaded(1)
 
· 测试新加载的.so是否成功
#snmpget -v 1 -c public localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0
       NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0 = INTEGER: 3
 
(2)修改配置文件snmpd.conf加载
在/usr/local/share/snmp/snmpd.conf文件中增加一行:
dlmod nstAgentPluginObject /oracle/agent/plugin/nstAgentPluginObject.so
 
3.2.4 测试代理
 
$snmpget -v 1 -c public localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0
NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0 = INTEGER: 123456
$snmpset -v 1 -c private localhost NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0 i 1000
NET-SNMP-TUTORIAL-MIB::nstAgentPluginObject.0 = INTEGER: 1000
调用设置后,你会发现在/oracle/agent/plugin/test.log中的内容增加一行: 1000 mode=0x3
 
3.3 Trap的开发
 
3.3.1 准备MIB 文件
 
在SNMPV1版本中MIB的TRAP定义与V2版本中不完全一样,V2版本开始叫notification。我们使用比较简单的V1版本来定义含有TRAP功能的MIB文件 UCD-TRAP-TEST-MIB.txt。
 
在/usr/local/share/snmp/snmp.conf中增加一行:mibs +UCD-TRAP-TEST-MIB
将UCD-TRAP-TEST-MIB.txt拷贝到/usr/local/share/snmp/mibs目录中。
 
3.3.2 Send trap
 
Trap的发送有几种实现情况,用户可以用snmp_add_var以及snmp_send等API编写应用来触发TRAP事件,也可以在MIB2C中mib2c.notify.conf配置模板在代理中实现TRAP的发送。发送TRAP的代码可以详细参考 mytrap.c。
编译:Gcc –o mytrap mytrap.c –lsnmp
执行:./mytrap
 
3.3.3 启动SNMPTRAPD 进程
 
· 修改snmptrapd.conf文件:
修改或产生/usr/loc1的snmptrapd进程默认下不接收任何TRAP,所以需要配置此文件,内容如下:al/share/snmp/snmptrapd.conf文件(在NET-SNMP5.4.1中好象没有自动生成此文件。)
authCommunity log,execute,net public
 
· 启动trapd进程
snmptrapd -P 或者snmptrapd  -f -Le
此命令将snmptrapd不做为后台进程运行,并将接收到的TRAP信息,以标准输出设备输出。
 
· 接收TRAP
2008-06-27 15:18:53 localhost [UDP: [127.0.0.1]:32787]:
DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (1052691) 2:55:26.91   SNMPv2-M
IB::sysLocation.0 = STRING: 我在家。。。        UCD-TRAP-TEST-MIB::demotraps# =
INTEGER: 1230   SNMPv2-MIB::snmpTrapOID.0 = OID: ccitt.1
 
3.4 程序清单
 
本文中使用的文件清单如下:
 
 
3.5 结束语
 
接触NET-SNMP时间较少,所以还有很多内容需要去发现与了解,不对之处,欢迎大家多多指正,不胜感激。
 
在本文中,您已经了解了使用 Net-SNMP的大致过程。本文介绍了如下几个方面:
(1)NET-SNMP的安装与配置。描述了NET-SNMP的安装以及配置情况。
(2)NET-SNMP的get、set、trap的操作。用代码实践了使用NET-SNMP API的操作全过程。
(3)使用NET-SNMP如何编写自己的代理(agent),本文详细介绍了使用动态库开发代理的方法,有机会将介绍其他两种方法。
 
SNMP协议本身是非常复杂的,使用NET-SNMP或其他SNMP的开发包,将使您忽略协议本身的细节,专注应用开发。