snmp-agent 初步了解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/backkom_jiu/article/details/79579064

入门级snmp agent开发,通过这篇文章可大致了解snmp agent的开发思路,主要参考了网上博客与官方文档,下方有链接。

用net-snmp扩展MIB库,实现方法可归结为四种:

1)一是静态库方式,通过修改配置头文件,在相应地方包含新引入的mib模块的.c和.h文件,然后重新编译库文件和扩展代码;这种方式不够灵活,每次修改扩展的MIB后,都需要重新编译snmpd和扩展的代码,再重新安装snmpd到系统中。

2)二是编译动态共享库,只需把新引入的MIB模块的.c和.h文件编译成动态库,通过设置能够让代理程序载入。

对于第二种方式,一需要编译成.so动态共享库,二需要原代理程序是否包含dlmod或load命令,三还要看系统是否支持。一般情况下仅支持Unix平台。

3)三是扩展一个子代理,让SNMPD以主代理的模式运行,对于SNMPD我们只要让它启动就可以,不需要任何的更改和配置,把子代理编译生成的程序运行起来就可以扩展自定义的MIB库。

4)用shell脚本来扩展

本文我们以第三种方法在linux上开发和测试

一、安装snmpd

1.1 安装包:

net-snmp-agent-libs-5.7.2-28.el7_4.1.x86_64
net-snmp-utils-5.7.2-28.el7_4.1.x86_64
net-snmp-libs-5.7.2-28.el7_4.1.x86_64
net-snmp-5.7.2-28.el7_4.1.x86_64
net-snmp-devel-5.7.2-28.el7_4.1.x86_64
net-snmp-perl-5.7.2-28.el7_4.1.x86_64

1.2 测试

systemctl restart snmpd.service
systemctl status snmpd.service
# 若出现running这表示安装成功

1.3 配置

vim /etc/snmp/snmpd.conf

master agentx  # master 是说该snmpd以主代理方式运行

rocommunity public  # rocommunity (只读对象)

rwcommunity public  # rwcommunity(读写对象)

默认主代理snmpd只支持agentx类型,而我们要开发的程序是一种子代理(subagent),是需要连snmpd的master agent的。

测试snmpd是否正常

执行snmpwalk -v2c -c public localhost 1.3.6.1.2.1.1,

输出类似如下方展示,则表示正常运行

SNMPv2-MIB::sysDescr.0 = STRING: Linux bogon 3.10.0-693.el7.x8664 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x8664

二、MIB库

首先MIB库有什么用?其实作为子代理来说,在server机器上,可以不用MIB库,MIB库只为了让用户访问时方便,有了MIB库,用户就不用记那么多和长的OID,比如把MIB放在windows机器上,在windows机器装一个支持MIB的软件,用该软件打开MIB库,只要点击相应的对象就可以自动发送snmp请求到server端,所以server端是可以不要MIB库的。

MIB 存放目录 /usr/share/snmp/mibs目录下,因为这个目录是snmpd的默认目录,只要把MIB库放入该目录就可以自动加载MIB库,否则需要修改/etc/snmp/snmp.conf文件,添加mibs +/path/to/XXX 并重启snmpd。

2.1 示例1

自定义MIB库,如下:

-- Test-MIB.my  
    Test-MIB DEFINITIONS ::= BEGIN  

        IMPORTS  
            OBJECT-GROUP, MODULE-COMPLIANCE, NOTIFICATION-GROUP      
                FROM SNMPv2-CONF      
            enterprises, Integer32, Unsigned32, OBJECT-TYPE, MODULE-IDENTITY,   
            NOTIFICATION-TYPE      
                FROM SNMPv2-SMI      
            DisplayString      
                FROM SNMPv2-TC;  

-- October 09, 2002 at 14:50 GMT  
        -- 1.3.6.1.4.1.16535  
        Test MODULE-IDENTITY   
            LAST-UPDATED "200210091450Z"        -- October 09, 2002 at 14:50 GMT  
            ORGANIZATION   
                ""    
            CONTACT-INFO   
                ""    
            DESCRIPTION   
                "Video's Server MIB."  
            ::= { enterprises 16535 }  

--  Node definitions  
-- This part will include all details about the Test.  
        -- 1.3.6.1.4.1.16535.1  
        Time OBJECT IDENTIFIER ::= { Test 1 }   


        -- 1.3.6.1.4.1.16535.1.1  
        GetTime OBJECT-TYPE  
            SYNTAX DisplayString (SIZE (0..100))  
            MAX-ACCESS read-only  
            STATUS current  
            DESCRIPTION  
                "Example : 2013/4/11"  
            ::= { Time 1 }  
    END  

-- Test-MIB.my  

该MIB库只有一个OID,即:1.3.6.1.4.1.16535.1.1

测试:

snmptranslate -Tp -IR Test-MIB::Test
# 如出现下面结果,表示MIB正常加载
+--Test(16535)
   |
   +--Time(1)
      |
      +-- -R-- String    GetTime(1)
               Textual Convention: DisplayString
               Size: 0..100

2.1 示例2

官方提供NET-SNMP-TUTORIAL-MIB.txt

NET-SNMP-TUTORIAL-MIB DEFINITIONS ::= BEGIN

-- A Comment!

-- IMPORTS: Include definitions from other mibs here, which is always
-- the first item in a MIB file.
IMPORTS
    netSnmpExamples                   FROM NET-SNMP-EXAMPLES-MIB
    OBJECT-TYPE, Integer32,
    MODULE-IDENTITY                       FROM SNMPv2-SMI
    MODULE-COMPLIANCE, OBJECT-GROUP       FROM SNMPv2-CONF;

--
-- A brief description and update information about this mib.
--
netSnmpTutorialMIB MODULE-IDENTITY
    LAST-UPDATED "200205290000Z"            -- 29 May 2002, midnight
    ORGANIZATION "net-snmp"
    CONTACT-INFO "postal:   Wes Hardaker
                            P.O. Box 382
                            Davis CA  95617

          email:    [email protected]
                 "
    DESCRIPTION  "A simple mib for demonstration purposes.
                 "
    ::= { netSnmpExamples 4 }

-- Define typical mib nodes, like where the objects are going to lie.
-- we'll prefix everything in this mib with nst (net snmp tutorial)
nstMIBObjects     OBJECT IDENTIFIER ::= { netSnmpTutorialMIB 1 }
nstMIBConformance OBJECT IDENTIFIER ::= { netSnmpTutorialMIB 2 }


-- define 3 objects, which will all be implemented in different ways
-- within the tutorial.

nstAgentModules   OBJECT IDENTIFIER ::= { nstMIBObjects 1 }


nstAgentModuleObject OBJECT-TYPE
    SYNTAX      Integer32
    MAX-ACCESS  read-write
    STATUS      current
    DESCRIPTION
    "This is an object that simply supports a writable integer
     when compiled into the agent.  See
     http://www.net-snmp.org/tutorial-5/toolkit/XXX for further
     implementation details."
    DEFVAL { 1 }
    ::= { nstAgentModules 1 }

nstAgentSubagentObject OBJECT-TYPE
    SYNTAX      Integer32
    MAX-ACCESS  read-write
    STATUS      current
    DESCRIPTION
    "This is an object that simply supports a writable integer
     when attached to the agent.  The object should be accessible
     when the agentx subagent containing this object is attached.
     See http://www.net-snmp.org/tutorial-5/toolkit/XXX for
     further implementation details."
    DEFVAL { 2 }
    ::= { nstAgentModules 2 }

nstAgentPluginObject OBJECT-TYPE
    SYNTAX      Integer32
    MAX-ACCESS  read-write
    STATUS      current
    DESCRIPTION
    "This is an object that simply supports a writable integer
     when attached to the agent.  This object should be accessible
     when the dynamic plugin has been loaded into the agent.  See
     http://www.net-snmp.org/tutorial-5/toolkit/XXX for further
     implementation details."
    DEFVAL { 3 }
    ::= { nstAgentModules 3 }

--
-- The above definitions produce a section of the mib tree that looks
-- like this (including our parent node, printed using the
-- snmptranslate command):
--
--
-- % snmptranslate -M+. -mNET-SNMP-TUTORIAL-MIB -Tp -IR netSnmpTutorialMIB
-- +-netSnmpTutorialMIB(4)
--   |
--   +-nstMIBObjects(1)
--   | |
--   | +-nstAgentModules(1)
--   |   |
--   |   +- -RW- Integer32 nstAgentModuleObject(1)
--   |   +- -RW- Integer32 nstAgentSubagentObject(2)
--   |   +- -RW- Integer32 nstAgentPluginObject(3)
--   |
--   +-nstMIBConformance(2)


-- You can then use the snmptranslate command to get the numerical or
-- textual OID representation of any piece of the tree:


-- Getting a OID:
--   % snmptranslate -M+. -mNET-SNMP-TUTORIAL-MIB -IR nstSSSecondsSinceChanged
--   .1.3.6.1.4.1.2021.13.4242.1.1.2


-- Getting a textual OID:
--   % snmptranslate -On -M+. -mNET-SNMP-TUTORIAL-MIB -IR nstSSSecondsSinceChanged
--   enterprises.ucdavis.ucdExperimental.netSnmpTutorialMIB.nstMIBObjects.nstScalarSet.nstSSSecondsSinceChanged


-- Getting a description:
--   % snmptranslate -Td -M+. -mNET-SNMP-TUTORIAL-MIB -IR nstSSSecondsSinceChanged 
--   .1.3.6.1.4.1.2021.13.4242.1.1.2
--   SYNTAX  TimeTicks
--   UNITS   "1/100th Seconds"
--   MAX-ACCESS      read-only
--   STATUS  current
--   DESCRIPTION     "This object indicates the number of 1/100th seconds since the
--           nstSSSimpleString object has changed.  If it is has never been
--           modified, it will be the time passed since the start of the
--           agent."



-- END:  Don't forget this!
END

这时我们 有了自定义的OID,但是还没有处理程序(子代理)

三、生成源代码

mib2c为PERL脚本编写,为了让PERL支持SNMP,您需要下载PERL CPAN FOR SNMP的包

3.1 示例1

mib2c可以根据mib库生成对应的源代码,有多种模板,这里我们要生成子代理的代码,所以选择是固定的,执行env MIBS=”+/usr/share/snmp/mibs/Test-MIB.my” mib2c Test,会引导你逐渐生成Test.h和Test.c, 先选2再选1,过程如下:

[root@localhost mibs]# env MIBS="+/etc/snmp/mibs/Test-MIB.my" mib2c Test  

writing to -  

mib2c has multiple configuration files depending on the type of  

code you need to write.  You must pick one depending on your need.  

You requested mib2c to be run on the following part of the MIB tree:  

  OID:                              Test  

  numeric translation:              .1.3.6.1.4.1.16535  

  number of scalars within:         1     

  number of tables within:          0     

  number of notifications within:   0     

First, do you want to generate code that is compatible with the   

ucd-snmp 4.X line of code, or code for the newer Net-SNMP 5.X code  

base (which provides a much greater choice of APIs to pick from):  

  1) ucd-snmp style code  

  2) Net-SNMP style code  

Select your choice : 2   

---

         GENERATING CODE FOR SCALAR OBJECTS:  

---

  It looks like you have some scalars in the mib you requested, so I  

  will now generate code for them if you wish.  You have two choices  

  for scalar API styles currently.  Pick between them, or choose not   

  to generate any code for the scalars:  

  1) If you're writing code for some generic scalars  

     (by hand use: "mib2c -c mib2c.scalar.conf Test")  

  2) If you want to magically "tie" integer variables to integer  

     scalars  
     (by hand use: "mib2c -c mib2c.int_watch.conf Test")  

  3) Don't generate any code for the scalars  

Select your choice: 1  

    using the mib2c.scalar.conf configuration file to generate your code.  

writing to Test.h  

writing to Test.c  



---

- NOTE WELL: The code generated by mib2c is only a template.  YOU  *  
- must fill in the code before it'll work most of the time.  In many *  
- cases, spots that MUST be edited within the files are marked with  *  
- /* XXX / or / TODO */ comments.                                  *  

---

running indent on Test.h  

running indent on Test.c  

mib2c已经统计出我们的mib库包含1个scalar变量,0个table变量,0个通知变量,Scalar就是包含我们常用的整型,字符串,时间等等数据类型。table就是scalar的一种集合,有一个和多个列组成,类似于数据库中的表。它必须具有索引项,用来按一定顺序检索表项,当然我们只写了一个标量的OID,不是表结构也不是通知结构

生成的Test.h如下:

/* 
 * Note: this file originally auto-generated by mib2c using 
 *        $ 
 */  
#ifndef TEST_H  
#define TEST_H  

/* 
 * function declarations  
 */  
void            init_Test(void);  
Netsnmp_Node_Handler handle_GetTime;  

#endif                          /* TEST_H */  

生成的Test.c文件如下:
[cpp] view plain copy
/* 
 * Note: this file originally auto-generated by mib2c using 
 *        $ 
 */  

#include <net-snmp/net-snmp-config.h>  
#include <net-snmp/net-snmp-includes.h>  
#include <net-snmp/agent/net-snmp-agent-includes.h>  
#include "Test.h"  

/** Initializes the Test module */  
void  
init_Test(void)  
{  
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };  

    DEBUGMSGTL(("Test", "Initializing\n"));  

    netsnmp_register_scalar(netsnmp_create_handler_registration  
                            ("GetTime", handle_GetTime, GetTime_oid,  
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));  
}  

int  
handle_GetTime(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.  
     */  

    switch (reqinfo->mode) {  

    case MODE_GET:  
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,  
                                 /* 
                                  * XXX: a pointer to the scalar's data  
                                  */ ,  
                                 /* 
                                  * XXX: the length of the data in bytes  
                                  */ );  
        break;  


    default:  
        /* 
         * we should never get here, so this is a really bad error  
         */  
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",  
                 reqinfo->mode);  
        return SNMP_ERR_GENERR;  
    }  

    return SNMP_ERR_NOERROR;  
}  

以上的代码都是自动生成的,我们没有写一行代码,到了这一步,我们需要把Test.c里面的 XXX改成自己的值,也就两行,修改后Test.c文件代码如下:

/* 
 * Note: this file originally auto-generated by mib2c using 
 *        $ 
 */  

#include <net-snmp/net-snmp-config.h>  
#include <net-snmp/net-snmp-includes.h>  
#include <net-snmp/agent/net-snmp-agent-includes.h>  
#include "Test.h"  
#include <time.h>  

/** Initializes the Test module */  
void  
init_Test(void)  
{  
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };  

    DEBUGMSGTL(("Test", "Initializing\n"));  

    netsnmp_register_scalar(netsnmp_create_handler_registration  
                            ("GetTime", handle_GetTime, GetTime_oid,  
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));  
}  

int  
handle_GetTime(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.  
     */  
    /*修改处*/
    time_t t;  
    switch (reqinfo->mode) {  
    case MODE_GET:  
        time(&t);  /*修改处*/
        char szTime[100]; /*修改处*/ 
        snprintf(szTime,100,"%s",ctime(&t));  /*修改处*/
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,  
                                 /* 
                                  * XXX: a pointer to the scalar's data  
                                  */ szTime/*修改处*/,  
                                 /* 
                                  * XXX: the length of the data in bytes  
                                  */ strlen(szTime))/*修改处*/;  
        break;  


    default:  
        /* 
         * we should never get here, so this is a really bad error  
         */  
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",  
                 reqinfo->mode);  
        return SNMP_ERR_GENERR;  
    }  

    return SNMP_ERR_NOERROR;  
} 

子代理程序基本就写完了,我们执行命令让我们的子代理生成可执行程序,执行
net-snmp-config --compile-subagent Test Test.c,生成了Test程序, 执行过程如下:

net-snmp-config程序生成了一个临时的C文件,临时文件并与Test.c一起编译,生成了Test程序后又删除了该临时文件。

3.2 测试

./Test
[root@bogon mibs]# snmpget -v2c -c public localhost 1.3.6.1.4.1.16535.1.1.0 
SNMPv2-SMI::enterprises.16535.1.1.0 = STRING: "Fri Mar 16 11:04:35 2018
"

3.3 示例2

nstAgentSubagentObject.c文件

/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.int_watch.conf,v 5.0 2002/04/20 07:30:13 hardaker Exp $
 */

#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>
#include "nstAgentSubagentObject.h"

/*
 * the variable we want to tie an OID to.  The agent will handle all
 * * GET and SET requests to this variable changing it's value as needed.
 */

static long      nstAgentSubagentObject = 2;

/*
 * our initialization routine, automatically called by the agent 
 * (to get called, the function name must match init_FILENAME()) 
 */
void
init_nstAgentSubagentObject(void)
{
    static oid      nstAgentSubagentObject_oid[] =
        { 1, 3, 6, 1, 4, 1, 8072, 2, 4, 1, 1, 2, 0 };

    /*
     * a debugging statement.  Run the agent with -DnstAgentSubagentObject to see
     * the output of this debugging statement. 
     */
    DEBUGMSGTL(("nstAgentSubagentObject",
                "Initializing the nstAgentSubagentObject module\n"));

    /*
     * the line below registers our variables defined above as
     * accessible and makes it writable.  A read only version of any
     * of these registration would merely call
     * register_read_only_long_instance() instead.  The functions
     * called below should be consistent with your MIB, however.
     * 
     * If we wanted a callback when the value was retrieved or set
     * (even though the details of doing this are handled for you),
     * you could change the NULL pointer below to a valid handler
     * function. 
     */
    DEBUGMSGTL(("nstAgentSubagentObject",
                "Initalizing nstAgentSubagentObject scalar integer.  Default value = %d\n",
                nstAgentSubagentObject));

    netsnmp_register_long_instance("nstAgentSubagentObject",
                                  nstAgentSubagentObject_oid,
                                  OID_LENGTH(nstAgentSubagentObject_oid),
                                  &nstAgentSubagentObject, NULL);

    DEBUGMSGTL(("nstAgentSubagentObject",
                "Done initalizing nstAgentSubagentObject module\n"));
}

nstAgentSubagentObject.h文件

/*
 * Note: this file originally auto-generated by mib2c using
 *        : mib2c.int_watch.conf,v 5.0 2002/04/20 07:30:13 hardaker Exp $
 */
#ifndef NSTAGENTSUBAGENTOBJECT_H
#define NSTAGENTSUBAGENTOBJECT_H

/*
 * function declarations 
 */
void            init_nstAgentSubagentObject(void);

#endif                          /* NSTAGENTSUBAGENTOBJECT_H */
net-snmp-config --compile-subagent mysubagent nstAgentSubagentObject.c

If all goes well, this should have produced a mysubagent binary file (like the script output above chose).

3.4 测试

# 使用非特权端口测试
snmpd -f -Lo -C --rwcommunity=public --master=agentx --agentXSocket=tcp:localhost:1705 udp:1161

snmpget -v 2c -c public localhost NET-SNMP-TUTORIAL-MIB::nstAgentSubagentObject.0

# NET-SNMP-TUTORIAL-MIB::nstAgentSubagentObject.0 = No Such Object available on this agent at this OID

 ./mysubagent -f -Lo -x  tcp:localhost:1705
 # 执行子代理
 ./mysubagent 

 snmpget -v 2c -c public localhost NET-SNMP-TUTORIAL-MIB::nstAgentSubagentObject.0
 # NET-SNMP-TUTORIAL-MIB::nstAgentSubagentObject.0 = INTEGER: 2

四、项目应用

我们再次执行net-snmp-config –compile-subagent Test Test.c,然后立刻Ctrl+c,时间要控制好,让net-snmp-config程序产生了临时的C文件,却没有删除它。打开临时文件,我们来看一下代码,200多行,本文只贴上main函数的重要部分,代码中都添加了注释,不难理解:


int main (int argc, char **argv)  
{  
  int arg;  
  char* cp = NULL;  
  int dont_fork = 0, do_help = 0;  

  while ((arg = getopt(argc, argv, "dD:fhHL:"  
#ifndef DISABLE_MIB_LOADING  
                       "m:M:"  
#endif /* DISABLE_MIB_LOADING */  
                       "n:"  
#ifndef DISABLE_MIB_LOADING  
                       "P:"  
#endif /* DISABLE_MIB_LOADING */  
                       "vx:")) != EOF) {  
    switch (arg) {  
    case 'D':/*这里省略多个case break,只是一些选项,没必要研究/ 
      break; 

    default: 
      fprintf(stderr, "invalid option: -%c\n", arg); 
      usage(argv[0]); 
      break; 
    } 
  } 

  if (do_help) { 
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, 
                           NETSNMP_DS_AGENT_NO_ROOT_ACCESS, 1); 
  } else { 
    /* we are a subagent  第一步:这里是告诉snmpd我们这个Test作为子代理*/  
    netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID,  
                           NETSNMP_DS_AGENT_ROLE, 1);  

    if (!dont_fork) {/* 这里是让Test程序变成守护进程,执行Test后可以在后台运行不会退出 */  
      if (netsnmp_daemonize(1, snmp_stderrlog_status()) != 0)  
        exit(1);  
    }  

    /* initialize tcpip, if necessary */  
    SOCK_STARTUP;  
  }  

  /* initialize the agent library 第二步*/  
  init_agent(app_name);  

  /* initialize your mib code here 第三步*/  
  init_Test();  

  /* Test will be used to read Test.conf files. 第四步 */  
  init_snmp("Test");  

  if (do_help) {  
    fprintf(stderr, "Configuration directives understood:\n");  
    read_config_print_usage("  ");  
    exit(0);  
  }  

  /* In case we received a request to stop (kill -TERM or kill -INT) */  
  netsnmp_running = 1;  
#ifdef SIGTERM  
  signal(SIGTERM, stop_server);  
#endif  
#ifdef SIGINT  
  signal(SIGINT, stop_server);  
#endif  
#ifdef SIGHUP  
  signal(SIGHUP, hup_handler);  
#endif  

  /* main loop here... */  
  while(netsnmp_running) {  
    if (reconfig) {  
      free_config();  
      read_configs();  
      reconfig = 0;  
    }  
    agent_check_and_process(1);  
  }  

  /* at shutdown time */  
  snmp_shutdown(app_name);  

  /* deinitialize your mib code here */  

  /* shutdown the agent library */  
  shutdown_agent();  
  SOCK_CLEANUP;  
  exit(0);  
}  

修改main后的Test.c文件如下:

/* 
 * Note: this file originally auto-generated by mib2c using 
 *        $ 
 */  

#include <net-snmp/net-snmp-config.h>  
#include <net-snmp/net-snmp-includes.h>  
#include <net-snmp/agent/net-snmp-agent-includes.h>  
#include "Test.h"  
#include <time.h>  

/** Initializes the Test module */  
void  
init_Test(void)  
{  
    const oid       GetTime_oid[] = { 1, 3, 6, 1, 4, 1, 16535, 1, 1 };  

    DEBUGMSGTL(("Test", "Initializing\n"));  

    netsnmp_register_scalar(netsnmp_create_handler_registration  
                            ("GetTime", handle_GetTime, GetTime_oid,  
                             OID_LENGTH(GetTime_oid), HANDLER_CAN_RONLY));  
}  

int  
handle_GetTime(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.  
     */  

    time_t t;  
    switch (reqinfo->mode) {  
    case MODE_GET:  
    time(&t);  
    char szTime[100];  
    snprintf(szTime,100,"%s",ctime(&t));  
        snmp_set_var_typed_value(requests->requestvb, ASN_OCTET_STR,  
                                 /* 
                                  * XXX: a pointer to the scalar's data  
                                  */ szTime,  
                                 /* 
                                  * XXX: the length of the data in bytes  
                                  */ strlen(szTime));  
        break;  


    default:  
        /* 
         * we should never get here, so this is a really bad error  
         */  
        snmp_log(LOG_ERR, "unknown mode (%d) in handle_GetTime\n",  
                 reqinfo->mode);  
        return SNMP_ERR_GENERR;  
    }  

    return SNMP_ERR_NOERROR;  
}  

static int keep_running;  
RETSIGTYPE stop_server(int __attribute__((unused)) a) {  
        keep_running = 0;  
}  

int main()  
{  
   const char *app_name = "Test";  
   /* we are a subagent */  
   netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);  

   /* initialize the agent library */  
   init_agent(app_name);  

   /* initialize your mib code here */  
   init_Test();  

   /* Test will be used to read Test.conf files. */  
   init_snmp("Test");  
   keep_running = 1;  
   while(keep_running)  
   {  
        agent_check_and_process(1);/* block every 1 second */  
   }  
   /* at shutdown time */  
   snmp_shutdown(app_name);  

   /* deinitialize your mib code here */  

   /* shutdown the agent library */  
   shutdown_agent();  
   return 0;  
}  

当snmpd stop的时候会调用stop_server,也就会注销我们的子代理。

编译一下,因为要加入到自己的项目中,所以推荐写入到Makefile中,本文就不写Makefile了,直接调用gcc命令生成(直接用net-snmp-config的参数就可以),然后我们启动snmpd,再执行Test程序,程序会block住,因为不是守护进程,而且main有循环,如下:

[root@bogon~]# ./Test   

NET-SNMP version 5.7.2 AgentX subagent connected

我们再调用snmpget来测试结果:

[root@bogon ~]# snmpget -v2c -c public localhost 1.3.6.1.4.1.16535.1.1.0  

SNMPv2-SMI::enterprises.16535.1.1.0 = STRING: "Thu Apr 11 02:39:17 2013  
"  

参考连接

自定义MIB扩展:http://blog.csdn.net/hepeng597/article/details/8782868
子代理官方参考:http://www.net-snmp.org/wiki/index.php/TUT:Writing_a_Subagent

猜你喜欢

转载自blog.csdn.net/backkom_jiu/article/details/79579064