xx110 SNMP代理开发说明

本文介绍了一种基于net-snmp-5.4.2的SNMP代理开发过程,包括需求分析、总体设计思路、具体节点实现方法及SNMPv3的安全配置。详细解释了如何实现get请求响应和发送trap告警。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1 SNMP 代理需求

(1) 提供设备相关的信息节点,供 SNMP 管理端查询,可支持 get get next walk 查询命令。提供 SN WAN IP CPU 占用率、内存使用率、进程个数、网络接口状态、网络接口当前流量、软件版本信息等节点信息。

(2) 提供对特俗事件到来时的发往 SNMP 管理端得 TRAP 告警功能。包括 CPU 使用率超阈值、内存超阈值、网口流量超阈值、 WAN IP 改变、设备重启等告警功能(暂未做)。

提供对 snmp v1 v2 版本的支持( v3 版本将在后期实现)

 

2 、总体设计思想

(1) 开发环境:基于开源软件 net-snmp- 5.4.2

(2) MIB 库来源:根据管理端的功能需求和节点的定义自行开发。

(3) 程序实现:利用 mib2c 工具将 MIB 库转化为代理程序框架,然后基于此框架进行进一步开发。最后将开发的代理程序静态编译进 net-snmp 框架中,它将注册到 net-snmp 框架中。注册的方法是再特定目录下(以 agent/mibgroup/bamboo 目录为例)分别建立一个 .c 文件和头文件,例如,名称分别取为 bamboo.c bamboo.h ,在 bamboo 中存放自己开发的所有 c 程序和头文件 ( xxx.c xxx.h) ,然后在 bamboo.h 中添加 module_require(xxx) ,并在 configure 时跟上:— with-mib_modules= bamboo ”来配置 Makefile ,使之在编译时加载 bamboo 文件下面的 xxx 文件(可以有多个 xxx 文件)。

 

3 get 信息节点的实现,以 cpu 占用率信息节点为例

(1) 自己编写该节点 MIB 库,由于 eX110 只有一个 CPU ,所以编写一个节点即可:

          hr_proc   OBJECT-TYPE

          SYNTAX      Integer32

              MAX-ACCESS  read-only

              STATUS      current

              DESCRIPTION "cpu usage"           

              ::= { my_cpu 2 }

(2) 利用 mib2c 工具 mib2c_old-api.conf 将该 mib 库转化为 get 信息节点的程序框架,然后基于该框架,添加需要实现的功能,部分代码如下:

 

/* 由系统基于 MIB 库生成的与节点相关的信息的结构体 */

#define    HRPROC_LOAD           2

struct variable4 hrproc_variables[] = {

    {HRPROC_LOAD, ASN_INTEGER, RONLY, var_hrproc, 3, {1, 2, 768}}

};

oid             hrproc_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 3, 3 };

 

 

/* 由系统生成的该节点初始化函数,在该初始化函数中注册了针对该节点的处理函数 */

void init_hr_proc(void)

{

    REGISTER_MIB("bamboo/hr_proc", hrproc_variables, variable4,

                 hrproc_variables_oid);

}

 

 

/*

  * header_hrproc :自己编写实现的函数,该函数将已注册到 net-snmp 的节点信息和管理端与访问的节点信息作比较。由于规定第一个 CPU 是用节点编号 768 开始,并且 eX110 只有一个 CPU 即要求该节点为 1.3.6 .1.2.1.25.3.3.1.2 . 768 ,所以将 netsnmp 中提供 head_generic() 函数中将已注册节点最后加“ 0 ”这步去掉, 直接将注册的该节点和跟管理端欲访问的节点作对比。

  * vp     IN      - 指向已注册节点数组的指针

  * name    IN/OUT  - 指向管理端欲访问节点的指针

  * length  IN/OUT  - length of IN/OUT oid's

  * exact   IN      - TRUE if an exact match was requested

  * var_len OUT     - length of variable or 0 if function returned

  * write_method

  */

 

Int header_hrproc(struct variable *vp,

              oid * name,

              size_t * length,

              int exact, size_t * var_len, WriteMethod ** write_method)

{

    oid             newname[MAX_OID_LEN];

    int              result;

 

    memcpy((char *) newname, (char *) vp->name,

           (int) vp->namelen * sizeof(oid));

    //newname[vp->namelen] = 0;  // 不需要在已注册节点后加“ 0 .

    result = snmp_oid_compare(name, *length, newname, vp->namelen);

    if ((exact && (result != 0)) || (!exact && (result >= 0)))

        return (MATCH_FAILED);

    memcpy((char *) name, (char *) newname,

           ((int) vp->namelen) * sizeof(oid));

    *length = vp->namelen;

 

    *write_method = 0;

    *var_len = sizeof(long);    /* default to 'long' results */

    return (MATCH_SUCCEEDED);

}

 

  /* System specific implementation functions 注册的处理函数 */

u_char   *var_hrproc(struct variable * vp,

           oid * name,

           size_t * length,

           int exact, size_t * var_len, WriteMethod ** write_method)

{

    int             proc_idx;

    static unsigned char string[SPRINT_MAX_LEN];

       FILE *file;

 

    proc_idx =

        header_hrproc(vp, name, length, exact, var_len, write_method);

    if (proc_idx == MATCH_FAILED)

        return NULL;

 

    switch (vp->magic) {

    case HRPROC_LOAD:

              get_cpu_usage(cpu_usage);   // 获取 CPU 使用率

        snprintf(string, sizeof(string), cpu_usage);            /* ++by Bamboo */

              long_return = atoi(string);

              if ((file = fopen("/var/run/snmp.log", "w")) == NULL)

              return;

              fprintf(file, "string is:%s , value is :%d/n", string, long_return);

              fclose(file);

             

        return (u_char *) &long_return ;  // 返回 long_return

    default:

        DEBUGMSGTL(("host/hr_proc", "unknown sub-id %d in var_hrproc/n",

                    vp->magic));

    }

    return NULL;

}

 

/*get cpu usage information for file loadavg5 and save it in string[] */

void

get_cpu_usage (char *string)

{

       FILE *file;

       char *str;

       int i = 0;

       char tmp[16];

      

       if ((file = fopen("/proc/loadavg5", "r")) == NULL)

              return;

       fread(tmp, 1, sizeof(tmp), file);

       fclose(file);

      

       str = tmp;

       while (*str != '/n') {

              if (*str == '.') {

                     str++;

              }

              else

                     *(string + i++) = *str++;

       }

       *(string + i) = '/0';

      

       return;

}

 

3 trap 告警的实现,以 cpu 使用率超标 Trap 的实现为例

(1) Trap 包需包含信息: a cpuoverflow trap 节点 1.3.6 .1.4.1.3902.151.11.10.3.5.1 (自己定义)

       b 、携带的其他信息携带变量:

SN oid 1.3.6 .1.2.1.47.1.1.1.1.11 ,和对应的值

CPU 使用率 oid 1.3.6 .1.2.1.25.3.3.1.2 ,和其对应的值

阈值 oid: 1.3.6.1.4.1.3902.151.11.10.3.3.9.1 ,和其对应的值

(2) 实现方法:参考示例 notfication.c ,并进行信号注册函数的修改,最终实现自己的功能。

(3) 程序实现:

/*cpu 超阈值告警初始化,即注册新号处理函数,每 30 秒执行一次 */

Void init_cpuoverflow(void)

{

    snmp_alarm_register(30 ,     /* seconds ,可自行设置时间间隔 */

                        SA_REPEAT,      /* repeat (every 30 seconds). */

                         send_cpuoverflow,       /* our callback */

                        NULL    /* no callback data needed */

        );

}

 

/* 要调用的回调函数的实现 */

Void send_cpuoverflow(unsigned int clientreg, void *clientarg)

{

    /*

     * define the OID for the cpuoverflow we're going to send

     * NET-SNMP-EXAMPLES-MIB::netSnmpExampleHeartbeatNotification

     */

       FILE *file;

    oid             cpuoverflow_oid[] =

        { 1, 3, 6, 1, 4, 1, 3902, 151, 11, 10, 3, 5, 1};

    size_t          cpuoverflow_oid_len = OID_LENGTH(cpuoverflow_oid);

    static u_long count = 0;

       u_char sn[64];

       u_char cpu_usage_str[8];

       unsigned cpu_usage;

       u_char cpu_threshold_str[8];

      

      

       get_cpu_usage(cpu_usage_str);

       cpu_usage = atoi(cpu_usage_str);

      

       snprintf(cpu_threshold_str, sizeof(cpu_threshold_str), nvram_safe_get("cpu_threshold"));

      

       /*if cpu percentage is small than threshold, do not trap*/

       if (cpu_usage < atoi(cpu_threshold_str))      // CPU 没超阈值,则返回。

              return;

      

       snprintf(sn, sizeof(sn), nvram_safe_get("dev_sn"));

      

    /*

     * In the cpuoverflow, we have to assign our cpuoverflow OID to

     * the snmpTrapOID.0 object. Here is it's definition.

     */

    oid             objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };

    size_t          objid_snmptrap_len = OID_LENGTH(objid_snmptrap);

 

    oid      devicesn_oid[]   = { 1, 3, 6, 1, 2, 1, 47, 1, 1, 1, 1, 11, 1 };

    size_t   devicesn_oid_len = OID_LENGTH(devicesn_oid);

      

    oid      hrproc_load_oid[]   = { 1, 3, 6, 1, 2, 1, 25, 3, 3, 1, 2, 768 };

    size_t   hrproc_load_oid_len = OID_LENGTH(hrproc_load_oid);

 

       oid      cpu_threshold_oid[]   = { 1, 3, 6, 1, 4, 1, 3902, 151, 11, 10, 3, 3, 9, 1, 0 };

    size_t   cpu_threshold_oid_len = OID_LENGTH(cpu_threshold_oid);

      

    /* here is where we store the variables to be sent in the trap */

netsnmp_variable_list *cpuoverflow_vars = NULL;  // 所有的绑定变量都将保存在该链表中

 

    /*add in the trap definition object 依次手动加载要绑定的变量到链表中 */

    snmp_varlist_add_variable(&cpuoverflow_vars,

                              objid_snmptrap, objid_snmptrap_len,

                              ASN_OBJECT_ID,

                               (u_char *) cpuoverflow_oid,

                              cpuoverflow_oid_len * sizeof(oid));

 

    snmp_varlist_add_variable(&cpuoverflow_vars,

                               devicesn_oid, devicesn_oid_len,

                              ASN_OCTET_STR,

                              sn,

                              strlen(sn));

 

    snmp_varlist_add_variable(&cpuoverflow_vars,

                               hrproc_load_oid, hrproc_load_oid_len,

                               ASN_INTEGER,

                                (u_char *)&cpu_usage,

                                                    sizeof(cpu_usage));

                                                   

       snmp_varlist_add_variable(&cpuoverflow_vars,

                               cpu_threshold_oid, cpu_threshold_oid_len,

                               ASN_OCTET_STR,

                                cpu_threshold_str,

                                                    strlen(cpu_threshold_str));

 

    ++count;  // trap 每执行一次,计数器加 1

    send_v2trap(cpuoverflow_vars);    // 发送 snmpv2 trap

      

    /* free the created cpuoverflow variable list */

    snmp_free_varbind(cpuoverflow_vars);

}

 

4 SNMP 移植到 eX110 的过程

(1) eX110 下的 Makefile 中添加:

 

build: user snmp  romfs linux image

snmp::     armeb-linux-strip $(IXPDIR)/user/net-snmp/sbin/snmpd

       cp $(IXPDIR)/user/net-snmp/sbin/snmpd  $(IXPDIR)/user/romfs/sbin

 

(2) user 下添加

snmp::     make -C snmp

snmp-install::   make -C snmp install

snmp-clean::  make -C snmp clean

 

(3) defaulte.c router_default[] 中添加:

       {"dev_sn", "123456789abcdefg", 0}, 

       {"oui", "cdsf", 0},                

       {"cpu_threshold", "20", 0},

       {"mem_threshold", "20", 0},

       {"recv_octet_threshold", "102400", 0},

       {"send_octet_threshold", "102400", 0},

       {"snmp_community", "public", 0},

       {"snmp_version", "v2c", 0},

       {"snmp_enable", "1", 0},

       {"snmp_server_ip", "0.0.0.0", 0},

       {"wan_alter_trap_enable", "1", 0},

       {"cpu_trap_enable", "1", 0},

       {"mem_trap_enable", "1", 0},

       {"recv_trap_enable", "1", 0},

       {"send_trap_enable", "1", 0},

       {"snmpv3_user", "navigator", 0},

       {"snmpv3_md5_auth", "navigator", 0},

       {"snmpv3_des_passwd", "navigator", 0},

 

(4) basic.c 中的 apply_action 中添加:

{ "snmpd_setup",         "snmpd",            16,    SERVICE_RESTART, NULL},

variable[] 中添加:

/*for snmpd*/

       {"dev_sn", "Dvice SN", NULL, NULL, FALSE}, 

       {"oui", "OUI Number", NULL, NULL, FALSE},                

       {"cpu_threshold", "CPU Threshold Value", NULL, NULL, FALSE},

       {"mem_threshold", "MEM Threshold Value", NULL, NULL, FALSE},

       {"recv_octet_threshold", "Recive Octet Threshold Value", NULL, NULL, FALSE},

       {"send_octet_threshold", "Send Octet Threshold Value", NULL, NULL, FALSE},

       {"snmp_community", "Read Only COMMUNITY", NULL, NULL, FALSE},

       {"snmp_version", "SNMP Version", NULL, NULL, FALSE},

       {"snmp_enable", "SNMP Enable", validate_choice, ARGV("0", "1"), FALSE},

       {"snmp_server_ip", "Mamager Server Number", NULL, NULL, FALSE},

       {"wan_alter_trap_enable", "WAN IP ALTER NOTIFY", validate_choice, ARGV("0", "1"), FALSE},

       {"cpu_trap_enable", "CPU TRAP  ENABLE", validate_choice, ARGV("0", "1"), FALSE},

       {"mem_trap_enable", "MEMORY TRAP  ENABLE", validate_choice, ARGV("0", "1"), FALSE},

       {"recv_trap_enable", "RECV OCTETS TRAP  ENABLE", validate_choice, ARGV("0", "1"), FALSE},

       {"send_trap_enable", "SEND OCTETS TRAP  ENABLE", validate_choice, ARGV("0", "1"), FALSE},

       {"snmpv3_user", "SNMPV3 USER NAME", NULL, NULL, FALSE}, 

       {"snmpv3_md5_auth", "SNMPV3 MD5 AUTHENTICATION CODEI", NULL, NULL, FALSE}, 

       {"snmpv3_des_passwd", "SNMPV3 DES PASSWORD", NULL, NULL, FALSE}, 

 

(5) service.c 中编写 start_snmpd() stop_snmpd()

 

int start_snmpd(void)

{

       FILE *fp;

       char ser_ip[16];

       char comnt[32];

       char version[8];

       char user[32];

       char md5_auth[32];

       char des_passwd[32];

       int snmp_enable;

       snmp_enable = atoi(nvram_safe_get("snmp_enable"));

       if (snmp_enable == 0)

              return 0;

 

       if (!nvram_invmatch("snmp_enable", "0"))

              return -1;

      

       strncpy(ser_ip,  nvram_safe_get("snmp_server_ip"), sizeof(ser_ip));

       strncpy(comnt, nvram_safe_get("snmp_community"), sizeof(comnt));

       strncpy(version, nvram_safe_get("snmp_version"), sizeof(version));

       strncpy(user, nvram_safe_get("snmpv3_user"), sizeof(user));

       strncpy(md5_auth, nvram_safe_get("snmpv3_md5_auth"), sizeof(md5_auth));

       strncpy(des_passwd, nvram_safe_get("snmpv3_des_passwd"), sizeof(des_passwd));

      

       /* Touch snmp config file */

       if (!(fp = fopen(SNMP_CONFIG_FILE, "w"))) {

              perror(SNMP_CONFIG_FILE);

              return errno;

       }

 

       fprintf(fp, "com2sec  snmpserver  default  %s/n",  comnt);

       if (!strcmp("v3",version))

              fprintf(fp, "group  ROGroup  usm  snmpserver/n");

       else

              fprintf(fp, "group  ROGroup  %s  snmpserver/n",  version);

       fprintf(fp, "view all   included  .1      80/n");

       fprintf(fp, "access  ROGroup  /"/"   any   noauth  exact   all   none  none/n");

       fprintf(fp, "syscontact Me <me@ssnsm.org>/n");

       fprintf(fp, "proc mountd/n");

       fprintf(fp, "proc ntalkd 4/n");

       fprintf(fp, "proc sendmail 10 1/n");

        fprintf(fp, "trap2sink   %s:162   %s/n", ser_ip, comnt);

       if (!strcmp("v3", version)) {

              fprintf(fp, "rwuser %s/n", user);

              fprintf(fp, "createUser %s MD5 %s DES %s/n",  user,  md5_auth, des_passwd);

       }

       fclose(fp);

       eval("snmpd",  "-c", SNMP_CONFIG_FILE);

       return 0; 

}

int stop_snmpd(void)

{

       int ret = 0;

 

       if (find_pid_by_name("snmpd")  < 0)

              return ret;

      

         ret = eval("killall", "-9", "snmpd");

      

       dprintf("done/n");

       return ret;

}

 

(6) rc.hz 中添加 extern int start_snmpd(void);   extern int stop_snmpd(void);

 

(7) start_single_service() 中添加:

else if (!strcmp(service, "snmpd"))

       {

              stop_snmpd();

              start_snmpd();

       }

 

start_servcies() 中添加:

start_snmpd();  //++ Bamboo     

 

7 )写该 snmpd 顶层 Makefile 中的 install:

       install::

              armeb-linux-strip ……/snmpd

              cp ……/snmpd    …..../user/romfs/sbin

 

5 SNMPv3 的实现

Snmp DES 加密功能的实现需要 openssl 的支持,所以应首先编译 openssl 开源软件包,最后需要两个静态库 libcrypto.a libssl.a ,以及它的头文件头文件。并在 snmpd 的配置文件 cross 中指定静态库的目录路径和静态库( -lcrypto –lssl 要按这个顺序),指定头文件的目录路径。

(1)     openssl 的编译,主要需要处理一些错误方能通过编译:

a openssl-0.9.8d/crypto/bio/bss_file.c 中以下代码注释掉

//#ifndef _FILE_OFFSET_BITS

//#define _FILE_OFFSET_BITS 64

//#endif

#endif

       b 报错没有 timeb.h 时,在报错的 .c 文件中 #undef TIMEB

c 去掉 openssl 顶层 Makefile 中“ build_all :”后面的 build_app build_test (我们要的只是两个静态库 libcrypto.a libssl.a ),并去掉 ”DIRS=” 后面的 app tests

2 )在配置 net-snmp 时,指定静态库的目录路径和静态库( -lcrypto –lssl 要按这个顺序),指定头文件的目录路径。

这样,便可以是 SNMP 加载进 DES 加密算法和 SHA1 认证(暂时不用该认证)。

 

3 SNMPv3 的配置文件 snmpd.conf 配置示例如下:

rwuser navigator

createUser navigator MD5 navigator DES navigator

group  ROGroup  usm  navigator

group  RWGroup  usm  navigator

view all   included  .1      80

access  ROGroup  ""   any   noauth  exact   all   none  none

access  RWGroup  ""   any   noauth  exact   all   all  none

syscontact Me <me@ssnsm.org>

syslocation Chengdu

trap2sink   192.168.16.8:162   public

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值