这里我们建立一个mib文件,命名为TEST-SET-MIB.txt,放在/usr/local/net-snmp/share/snmp/mibs/目录下因为这个目录是snmpd的默认目录,只要把MIB库放入该目录就可以自动加载MIB库,否则需要修改snmpd.conf文件,自定义的MIB文件如下:
--开始
TEST-SET-MIB DEFINITIONS ::= BEGIN
--引入部分
IMPORTS
enterprises
FROM RFC1155-SMI
Integer32,OBJECT-TYPE
FROM SNMPv2-SMI
DisplayString
FROM SNMPv2-TC
TEXTUAL-CONVENTION
FROM SNMPv2-TC; --引用结束,用分号
--定义节点
--enterprises的OID是1.3.6.1.4
testSet OBJECT IDENTIFIER ::= {enterprises 77587}
writeObject OBJECT IDENTIFIER ::= {testSet 1}
writeObject OBJECT-TYPE --对象名称
SYNTAX DisplayString --类型
MAX-ACCESS read-write --访问方式
STATUS current --状态
DESCRIPTION "test write" --描述
::= {testSet 1} --父节点
--结束定义
END
写完后我们测一个MIB库有没有问题,在linux机器上用snmptranslate-Tp -IR TEST-SET-MIB::testSet显示结果如下:(这个测试不需要启动snmpd进程)
[root@localhostbin]# ./snmptranslate -Tp -IR TEST-SET-MIB::testSet
+--testSet(77587)
|
+-- -RW- String writeObject(1)
Textual Convention: DisplayString
Size: 0..255
OK,snmp自动发现了这个MIB库, 有了自定义的OID,接下来开始添加处理程序。
执行envMIBS="+/usr/local/net-snmp/share/snmp/mibs/TEST-SET-MIB.txt" ./mib2c testSet,会引导你逐渐生成testSet.h和testSet.c,先选2再选1。
具体生成过程参考上一篇文档
生成的testSet.h如下
* Note: this file originally auto-generated by mib2c using
* $
*/
#ifndef TESTSET_H
#define TESTSET_H
/*
* function declarations
*/
void init_testSet(void);
Netsnmp_Node_Handler handle_writeObject;
#endif /* TESTSET_H */
经过修改的testSet.c文件如下,有一些生成的注释文件去掉了
/*
* Note: this file originally auto-generated by mib2c using
* $
*/
#include
#include
#include
#include "testSet.h"
//这里是添加的,buf用于保存控制端设置的值,也用于返回。
#define BUFSIZE 1024
static char buf[BUFSIZE] = "test Write"; //给一个默认值
/** Initializes the testSet module */
void
init_testSet(void)
{
const oid writeObject_oid[] = { 1, 3, 6, 1, 4, 1, 77587, 1 };
DEBUGMSGTL(("testSet", "Initializing\n"));
netsnmp_register_scalar(netsnmp_create_handler_registration
("writeObject", handle_writeObject,
writeObject_oid, OID_LENGTH(writeObject_oid),
HANDLER_CAN_RWRITE));
}
int
handle_writeObject(netsnmp_mib_handler *handler,
netsnmp_handler_registration *reginfo,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
int ret;
switch (reqinfo->mode) {
//是获取操作
case MODE_GET:
snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,
/*这里填buf,用于返回数据给控制端*/ buf /* XXX: a pointer to the scalar's data */,
/*这里是buf数据字节数,注意writeObject类型*/ strlen(buf) /* XXX: the length of the data in bytes */);
break;
/*
* SET REQUEST
*
* multiple states in the transaction. See:
* http://www.net-snmp.org/tutorial-5/toolkit/mib_module/set-actions.jpg
*/
//下面是设置操作的,也就是snmpset
case MODE_SET_RESERVE1: //这个不管它
/* or you could use netsnmp_check_vb_type_and_size instead */
ret = netsnmp_check_vb_type(requests->requestvb, ASN_OCTET_STR);
if ( ret != SNMP_ERR_NOERROR ) {
netsnmp_set_request_error(reqinfo, requests, ret );
}
break;
case MODE_SET_RESERVE2:
/* XXX malloc "undo" storage buffer */
//我们不需要动态申请内存,直接略过
if ( 0/* XXX if malloc, or whatever, failed: */ ) {
netsnmp_set_request_error(reqinfo, requests,SNMP_ERR_RESOURCEUNAVAILABLE);
}
break;
case MODE_SET_FREE:
/*
* XXX: free resources allocated in RESERVE1 and/or
* RESERVE2. Something failed somewhere, and the states
* below won't be called.
*/
break;
// 这里是我们的重点,控制端传过来的数据就在这里获取
case MODE_SET_ACTION:
/*
* XXX: perform the value change here
/* 获取控制端使用snmpset传来的数据 */
memcpy(buf,requests->requestvb->buf,requests->requestvb->val_len);
if ( 0/* XXX: error? */ ) {//这个先不管了
netsnmp_set_request_error(reqinfo, requests, 0/* some error */);
}
break;
case MODE_SET_COMMIT:
/*
* XXX: delete temporary storage
*/
if ( 0/* XXX: error? */ ) {
/*
* try _really_really_ hard to never get to this point
*/
netsnmp_set_request_error(reqinfo, requests,SNMP_ERR_COMMITFAILED);
}
break;
case MODE_SET_UNDO:
/*
* XXX: UNDO and return to previous value for the object
*/
if ( 0/* XXX: error? */ ) {
/*
* try _really_really_ hard to never get to this point
*/
netsnmp_set_request_error(reqinfo, requests,SNMP_ERR_UNDOFAILED);
}
break;
default:
/*
* we should never get here, so this is a really bad error
*/
snmp_log(LOG_ERR, "unknown mode (%d) in handle_writeObject\n",reqinfo->mode);
return SNMP_ERR_GENERR;
}
return SNMP_ERR_NOERROR;
}
把testSet.c和testSet.h复制到/net-snmp-5.7.3/agent/mibgroups/路径下
设置编译参数(红色部分即为加上我们自己的mib模块)
[[email protected]]# ./configure --prefix=/usr/local/net-snmp --with-mib-modules="testSet"
查看文件net-snmp-5.7.3/agent/mibgroup/mib_module_inits.h,发现已经添加到初始化中。
/*This file is automatically generated by configure. Do not modify by hand. */
if (should_init("testSet"))init_testSet();
编译并安装
[[email protected]]# make
[[email protected]]# make install
启动snmpd服务
[root@localhostsbin]# ./snmpd -f -Le
Turning on AgentXmaster support.
NET-SNMP version5.7.3
No Shmem line in/proc/meminfo
我们再调用snmpget来测试结果:
[root@localhostbin]# ./snmpget -c public -v 2c localhost 1.3.6.1.4.1.77587.1.0
SNMPv2-SMI::enterprises.77587.1.0= STRING: "test Write"
设置时提示报错,这和snmpd的配置文件的权限有关。
[root@localhostbin]# ./snmpset -c public -v 2c localhost 1.3.6.1.4.1.77587.1.0 s"hello world"
Error in packet.
Reason: noAccess
Failed object:SNMPv2-SMI::enterprises.77587.1.0
打开snmpd.conf文件,添加如下一行,然后重启snmpd
rwcommunitypublic
再通过./snmpset-c public -v 2c localhost 1.3.6.1.4.1.77587.1.0 s "hello world"设置以后,有如下提示,说明设置成功了。
SNMPv2-SMI::enterprises.77587.1.0= STRING: "hello world"
然后再次调用snmpget
[root@localhostbin]# ./snmpget -c public -v 2c localhost 1.3.6.1.4.1.77587.1.0
SNMPv2-SMI::enterprises.77587.1.0= STRING: "hello world"
至此我们添加自定义MIB Set操作成功!