编程技术到不存在问题,可是要快熟编写net-snmp代理到还是遇到了不少小问题,网上资料也比较少,通过官网和《深入理解Net-SNMP》一书,基本搞定了net-snmp开发代理的过程,其他的都是编程的工作了。
本文的目的也是希望可以快速通过net-snmp实现代理的开发,本文基本概念就省了,直接开始如何开始开发一个自定义代理。
开发一个代理:
(1)需要编写自己的MIB库
建议使用Mib Editor(中国人写的,强),MG-SOFT的MIB工具在我的Windows10上出现崩溃和不能打开保存的文件。Mib Editor需要安装JDK1.6,请到Oracle官网找历史版本。
Mib Editor估计是采用Eclipse的框架写的,先建立一个项目,然后新建一个Mib文件(新建时“类别”选择MIB,不要选择子节点,就在“文件类型”中看到“空MIB文件”)
(2)编译net-snmp源码
在开发阶段,建议使用动态库的方式开发,如果后期觉得效率有问题,或者在嵌入式系系统中运行时,才考虑使用静态编译的方式(静态编译很耗时间,动态库一样可以用GDB调试)。
编译net-snmp源码的方式的简单方式如下:
./configure
make
make install
当然,./configure有一堆的参数,入门时先不需要关心,缺省就可以用了。
编译后,还需要生产一个配置文件,这个在《深入理解Net-SNMP》一书中有详细的步骤。本文后面会贴上我生成的配置文件,保配置文件保存到/usr/local/share/snmp/snmpd.conf。
(3)使用mib2c工具生成测试代码
这里,我们对于标量(普通的量)采用mib2c.scalar.conf, 对于表格采用mib2c.iterator_access.conf。
对于标量生成的C代码很简单,对于只读标量,只需要实现GET方法即可。
比如:mib2c -c mib2c.scalar.conf WILLSERVICE-ROADLAMP-GATEWAY-MIB::lampController
int
handle_controllerCount(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
/* We are never called for a GETNEXT if it's registered as a
"instance", as it's "magically" handled for us. */
/* a instance handler also only hands us one request at a time, so
we don't need to loop over a list of requests; we'll only get one. */
lampctrl_t* plampctrl = lampctrl_get_object();
switch(reqinfo->mode) {
case MODE_GET:
snmp_set_var_typed_value(requests->requestvb, ASN_COUNTER,
&plampctrl->count, sizeof(plampctrl->count));
break;
default:
/* we should never get here, so this is a really bad error */
snmp_log(LOG_ERR, "unknown mode (%d) in handle_controllerCount\n", reqinfo->mode );
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
主要在于snmp_set_var_typed_value函数的实现,后面两个参数就是返回变量的指针和变量数据的长度。该示例为返回控制器数量。MIB配置如下:
controllerCount OBJECT-TYPE
SYNTAX Counter32
MAX-ACCESS read-only
STATUS current
DESCRIPTION
"Communication node count."
::= { lampController 1 }
(4)编译mib2c生成的代码
该过程说起来简单,尤其是静态编译而言,可是对动态编译而言,就需要自己去摸索了。
静态编译的方法:
重新使用configure,并指定需要编译的代理模块:
编译静态模块官网的例子是:
./configure --with-mib-modules="nstAgentModuleObject"
编译动态模块的官网例子是:
$ cc `net-snmp-config --cflags` -fPIC -shared -g -O0 -o nstAgentPluginObject.so nstAgentPluginObject.c `net-snmp-config --libs`对于简单的标量开发而言,以上方法没有问题,对于表格的情况,mib2c生成了多个文件,需要写自己的Makefile来编译。
简单的Makefile如下:
#!/bin/sh
LIB=$(patsubst %.c,%.o,$(wildcard *.c))
DLL=lampController.so
CFLAGS+= -fno-strict-aliasing -g -O2 -Ulinux -Dlinux=linux -D_REENTRANT -D_GNU_SOURCE -fno-strict-aliasing -fstack-protector -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/lib64/perl5/CORE -I. -I/usr/local/include
DLLLDFLAGS=`net-snmp-config --libs`
all:$(DLL)
$(DLL):%.so:$(LIB)
gcc $(DLLLDFLAGS) -shared -rdynamic -g $^ -o $@
$(LIB):%.o:%.c
gcc -c $(CFLAGS) -g -dH -fPIC -Wall $^ -o $@
clean:
rm -rf *.o
注意:net-snmp-config–cflags生产编译标志,最好不直接使用,而是把生成后的内容写到Makefile文件中,其中有一个-pipe选项导致文件没有编译通过,也会生产目标文件,这样就会出现有错误,也可能把程序编译了,从而出现问题。
以上Makefile可以把目录下的文件都编译生成一个动态库,需要修改DLL的宏定义。
假如我们通过mib2c生成代码后
注意:net-snmp框架是通过模块名来加载动态库的函数的,比如:
dlmod lampController /home/oracle/yhb/soloarlamp/bin/liblampcontroller.so
net-snmp会在该动态库中查找init_lampController函数,来注册OID。
dlmod 需要添加到snmp的配置文件中,缺省位置:/usr/local/share/snmp/snmpd.conf
(5)运行和测试
启动snmp进程,通过-D可以打开调试:
snmpd -f -Lo -Ddlmod,lampController
此时既可以通过snmpwalk取得对应的数据了:
比如:
snmpget -v2c -c public localhost WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerCount.0
就可以返回:
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerCount.0 = Counter32: 2
注意后面的0,最好使用snmpwalk命令来获取数据:
[oracle@jkj mibs]$ snmpwalk -v2c -c public localhost WILLSERVICE-ROADLAMP-GATEWAY-MIB::lampController
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerCount.0 = Counter32: 2
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerId."A00001" = STRING: "A00001"
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerId."A00002" = STRING: "A00002"
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerUpTime."A00001" = Timeticks: (1450859937) 167 days, 22:09:59.37
WILLSERVICE-ROADLAMP-GATEWAY-MIB::controllerUpTime."A00002" = Timeticks: (1450859943) 167 days, 22:09:59.43
(对于net-snmp的使用,请参见我的另外一篇文章)
(本来打算弄一个教学视频的,等有时间的时候弄一个,有问题的,请回帖,我会回答问题的)