zoukankan      html  css  js  c++  java
  • 【网络编程】——ne-snmp开发实例1

    net-snmp扩展有多种方式,在此只介绍两种——动态库扩展,静态库扩展。

    在做net-snmp开发之前,首先确定net-snmp相关的软件是否安装。

    rpm -qa | grep snmp
    net-snmp-5.3.1-19.el5
    net-snmp-perl-5.3.1-19.el5
    net-snmp-libs-5.3.1-19.el5
    net-snmp-utils-5.3.1-19.el5
    net-snmp-devel-5.3.1-19.el5

    动态库扩展

    使用动态库扩展net-snmp4个步骤,分别是:

    1:编写MIB库。

    2:根据MIB库生成源代码。可以使用mib2c工具。

    3:编译。

    4:修改配置文件。

    编写MIB

      假设我们现在需要使用snmp来获取某个服务器上的硬盘使用情况——df命令显示的数据。首先我们需要一个字段来表示HostName,然后我们需要一个表来存放磁盘的信息DiskInfoTable

      1 DISK-SNMP-MIB DEFINITIONS ::= BEGIN
      2 IMPORTS
      3     MODULE-IDENTITY, enterprises, OBJECT-TYPE, Integer32,
      4     NOTIFICATION-TYPE                       FROM SNMPv2-SMI
      5     SnmpAdminString                         FROM SNMP-FRAMEWORK-MIB
      6     netSnmp                                 FROM NET-SNMP-MIB
      7     RowStatus, StorageType ,DisplayString   FROM SNMPv2-TC
      8     InetAddressType, InetAddress            FROM INET-ADDRESS-MIB
      9 ;
     10 DiskCheck MODULE-IDENTITY
     11     LAST-UPDATED "201602170000Z"
     12     ORGANIZATION "www.cnblogs.com/ngnetboy"
     13     CONTACT-INFO
     14         "postal: none
     15         email: ngnetboy@163.com
     16         "   
     17     DESCRIPTION
     18         "check the disk"
     19     REVISION "201602170000Z"
     20     DESCRIPTION "First draft"
     21     ::= { enterprises 888888 }
     22 
     23 root OBJECT IDENTIFIER ::= {DiskCheck 1}
     24 
     25 HostName OBJECT IDENTIFIER ::= {root 1}
     26 DiskInfoTable OBJECT IDENTIFIER ::= {root 2}
     27 
     28 HostName OBJECT-TYPE
     29     SYNTAX      DisplayString
     30     ACCESS      read-only
     31     STATUS      current
     32     DESCRIPTION
     33         "PC is name"
     34 ::= {root 1}
     35 DiskInfoTable OBJECT-TYPE
     36     SYNTAX      SEQUENCE OF DiskInfoEntry
     37     ACCESS      not-accessible
     38     STATUS      current
     39     DESCRIPTION "The disk's info include size used avail capacity and mounted on"
     40     ::= {root 2}
     41 
     42 diskInfoEntry OBJECT-TYPE
     43     SYNTAX      DiskInfoEntry
     44     ACCESS      not-accessible
     45     STATUS      current
     46     DESCRIPTION "A row describing a given working group"
     47     INDEX       { Filesystem }
     48     ::= {DiskInfoTable 1}
     49 
     50 DiskInfoEntry ::= SEQUENCE {
     51     Filesystem  DisplayString
     52     size        DisplayString
     53     used        DisplayString
     54     avail       DisplayString
     55     capacity    DisplayString
     56     mountedOn   DisplayString
     57 }
     58 
     59 Filesystem OBJECT-TYPE
     60     SYNTAX  DisplayString
     61     ACCESS  read-only
     62     STATUS  current
     63     DESCRIPTION "name of the disks"
     64     ::= {diskInfoEntry 1}
     65 
     66 size    OBJECT-TYPE
     67     SYNTAX  DisplayString
     68     ACCESS  read-only
     69     STATUS  current
     70     DESCRIPTION "size of the disks"
     71 ::= {diskInfoEntry 2}
     72 
     73 used    OBJECT-TYPE
     74     SYNTAX  DisplayString
     75     ACCESS  read-only
     76     STATUS  current
     77     DESCRIPTION "used of the disks"
     78     ::= {diskInfoEntry 3}
     79 
     80 avail   OBJECT-TYPE
     81     SYNTAX  DisplayString
     82     ACCESS  read-only
     83     STATUS  current
     84     DESCRIPTION "avail of the disks"
     85     ::= {diskInfoEntry 4}
     86 
     87 capacity    OBJECT-TYPE
     88     SYNTAX  DisplayString
     89     ACCESS  read-only
     90     STATUS  current
     91     DESCRIPTION "capacity of the disks"
     92     ::= {diskInfoEntry 5}
     93 
     94 mountedOn   OBJECT-TYPE
     95     SYNTAX  DisplayString
     96     ACCESS  read-only
     97     STATUS  current
     98     DESCRIPTION "mounted_on of the disks"
     99     ::= {diskInfoEntry 6}
    100 END
    DISK-SNMP-MIB

      使用snmptranslate -Tp -IR DISK-SNMP-MIB::DiskCheck 命令查看mib

     1 [root@localhost net-snmp]# snmptranslate -Tp -IR DISK-SNMP-MIB::DiskCheck
     2 +--DiskCheck(888888)
     3    |
     4    +--root(1)
     5       |
     6       +-- -R-- String    HostName(1)
     7       |        Textual Convention: DisplayString
     8       |        Size: 0..255
     9       |
    10       +--DiskInfoTable(2)
    11          |
    12          +--diskInfoEntry(1)
    13             |  Index: Filesystem
    14             |
    15             +-- -R-- String    Filesystem(1)
    16             |        Textual Convention: DisplayString
    17             |        Size: 0..255
    18             +-- -R-- String    size(2)
    19             |        Textual Convention: DisplayString
    20             |        Size: 0..255
    21             +-- -R-- String    used(3)
    22             |        Textual Convention: DisplayString
    23             |        Size: 0..255
    24             +-- -R-- String    avail(4)
    25             |        Textual Convention: DisplayString
    26             |        Size: 0..255
    27             +-- -R-- String    capacity(5)
    28             |        Textual Convention: DisplayString
    29             |        Size: 0..255
    30             +-- -R-- String    mountedOn(6)
    31                      Textual Convention: DisplayString
    32                      Size: 0..255
    MIB tree

      需要注意的是,我们是在1.3.6.1.4.1下的enterprises节点下扩展,因此需要在IMPORTS中添加enterprises。如果需要其他类型,也需要在IMPORTS中添加,比如DisplayString, Integer32 ...

    根据MIB库生成源代码

      一种比较懒的方式就是使用mib2c工具,根据不同的模板生成代码。本文中使用两个模板——mib2c.scalar.confmib2c.iterate.conf。前者是专门生成一个简单的变量,后者是生成一个table。 

      以上的MIBHostName是一个简单变量,DiskInfoTable是一个表。因此可以使用以下命令:

    mib2c -c mib2c.scalar.conf HostName
    mib2c -c mib2c.iterate.conf DiskInfoTable

      以上命令会分别生成一个.c 和 .h 的文件。只需要修改生成的.c .h文件即可。生成简单变量的代码比较简单,只需要修改一个地方即可,下面是一个diff的截图:

      只需要在XXX的地方添加即可。有注释,不再赘述。

      相比而言生成表的代码会复杂一些。需要改动的地方也相当的多。表:顾名思义就是可以存储多个相同结构的结构体数组,这个结构体数组并不是一个顺序的存储方式,而是一个链式的。在刚开始通过DiskInfoTable_createEntry创建链表节点,然后通过遍历链表的方式,通过索引为每一组数据进行赋值。

      首先在DiskInfoTable_get_first_data_point函数的开始,创建链表节点,并为节点赋值。我们定义一个函数为 void read_data(void); 此函数主要用来创建节点,赋值节点。做完这些,主要的功能代码就完成了。接下来就是修复编译的一些bug。由于这些代码都是使用脚本生成的,在很多地方都不规范,我们需要手动改一些东西:

    1:在initialize_table_DiskInfoTable函数中,

      table_info->min_column = XXX;
      table_info->max_column = YYY; 

      XXXYYY表示输出的最小/大列。在相对应的.h文件中有定义的宏,选取最小的和最大的赋值即可。

    2:修改struct DiskInfoTable_entry{}; 由于我们在mib库中定义了Index——Filesystem,在生成结构体的时候你会发现有两个Filesystem字段,删除一个即可,同样你会发现所有的string类型的字段都变成了char型,再此需要把char型数据改为char数组。

    3:在DiskInfoTable_createEntry函数中,会有一个对Index赋值的过程,代码中使用的是 a=b 的形式,由于我们的Filesystemstring类型的,此时需要改为 strncpy/strcpy等字符串赋值的函数。

    4DiskInfoTable_get_first_data_point函数中少了一个赋值,加上即可:

    *my_data_context = DiskInfoTable_head;

    5DiskInfoTable_get_next_data_point函数中少了一个返回值,加上即可:

    return put_index_data; 

    6DiskInfoTable_handler函数中需要修改的地方有两类,第一类是使用snmp_set_var_typed_value设置节点value的时候,需要把字段改成u_char * 类型。第二类是在每个switch分支后,判断table_entry是否为空,如果为空则调用netsnmp_set_request_error返回出错信息。防止用户在访问snmp时导致snmp无法相应的问题。

    以下是修改后的全部代码:

      1 /*
      2  * Note: this file originally auto-generated by mib2c using
      3  *  : mib2c.iterate.conf,v 5.17 2005/05/09 08:13:45 dts12 Exp $
      4  */
      5 
      6 #include <net-snmp/net-snmp-config.h>
      7 #include <net-snmp/net-snmp-includes.h>
      8 #include <net-snmp/agent/net-snmp-agent-includes.h>
      9 #include "DiskInfoTable.h"
     10 typedef struct _disk_info {
     11         char            filesystem[64];
     12         char            size[64];
     13         char            used[64];
     14         char            avail[64];
     15         char            capacity[64];
     16         char            mountedOn[64];
     17 }disk_info_t;
     18 
     19 disk_info_t disk_info[MAX_DISK] = {
     20         {"/dev/mapper", "19G", "2.6G", "15G", "15%", "/"},
     21         {"/dev/sda1", "99M", "12M", "83M", "13%", "/boot"},
     22         {"tmpfs", "252M", "0", "252M", "0%", "/dev/shm"},
     23         {"/dev/scd1", "2.8G", "2.8G", "0", "100%", "/media/"},
     24 };
     25 
     26 /** Initializes the DiskInfoTable module */
     27         void
     28 init_DiskInfoTable(void)
     29 {
     30         /*
     31          * here we initialize all the tables we're planning on supporting 
     32          */
     33         initialize_table_DiskInfoTable();
     34 }
     35 
     36 /** Initialize the DiskInfoTable table by defining its contents and how it's structured */
     37         void
     38 initialize_table_DiskInfoTable(void)
     39 {
     40         static oid      DiskInfoTable_oid[] =
     41         { 1, 3, 6, 1, 4, 1, 888888, 1, 2 };
     42         size_t          DiskInfoTable_oid_len = OID_LENGTH(DiskInfoTable_oid);
     43         netsnmp_handler_registration *reg;
     44         netsnmp_iterator_info *iinfo;
     45         netsnmp_table_registration_info *table_info;
     46 
     47         reg =
     48                 netsnmp_create_handler_registration("DiskInfoTable",
     49                                 DiskInfoTable_handler,
     50                                 DiskInfoTable_oid,
     51                                 DiskInfoTable_oid_len,
     52                                 HANDLER_CAN_RONLY);
     53 
     54         table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
     55         netsnmp_table_helper_add_indexes(table_info, ASN_OCTET_STR, /* index: Filesystem */
     56                         0);
     57         table_info->min_column = COLUMN_FILESYSTEM;
     58         table_info->max_column = COLUMN_MOUNTEDON;
     59 
     60         iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
     61         iinfo->get_first_data_point = DiskInfoTable_get_first_data_point;
     62         iinfo->get_next_data_point = DiskInfoTable_get_next_data_point;
     63         iinfo->table_reginfo = table_info;
     64 
     65         netsnmp_register_table_iterator(reg, iinfo);
     66 
     67         /*
     68          * Initialise the contents of the table here 
     69          */
     70 }
     71 
     72 /*
     73  * Typical data structure for a row entry 
     74  */
     75 struct DiskInfoTable_entry {
     76         /*
     77          * Column values 
     78          */
     79         char            Filesystem[16];
     80         char            size[8];
     81         char            used[8];
     82         char            avail[8];
     83         char            capacity[8];
     84         char            mountedOn[16];
     85         /*
     86          * Illustrate using a simple linked list 
     87          */
     88         int             valid;
     89         struct DiskInfoTable_entry *next;
     90 };
     91 
     92 struct DiskInfoTable_entry *DiskInfoTable_head;
     93 
     94 /*
     95  * create a new row in the (unsorted) table 
     96  */
     97         struct DiskInfoTable_entry *
     98 DiskInfoTable_createEntry(char *Filesystem)
     99 {
    100         struct DiskInfoTable_entry *entry;
    101 
    102         entry = SNMP_MALLOC_TYPEDEF(struct DiskInfoTable_entry);
    103         if (!entry)
    104                 return NULL;
    105 
    106         //entry->Filesystem = Filesystem;
    107         strncpy(entry->Filesystem, Filesystem, strlen(Filesystem));
    108         entry->next = DiskInfoTable_head;
    109         DiskInfoTable_head = entry;
    110         return entry;
    111 }
    112 /*
    113  * remove a row from the table 
    114  */
    115         void
    116 DiskInfoTable_removeEntry(struct DiskInfoTable_entry *entry)
    117 {
    118         struct DiskInfoTable_entry *ptr, *prev;
    119 
    120         if (!entry)
    121                 return;                 /* Nothing to remove */
    122 
    123         for (ptr = DiskInfoTable_head, prev = NULL;
    124                         ptr != NULL; prev = ptr, ptr = ptr->next) {
    125                 if (ptr == entry)
    126                         break;
    127         }
    128         if (!ptr)
    129                 return;                 /* Can't find it */
    130 
    131         if (prev == NULL)
    132                 DiskInfoTable_head = ptr->next;
    133         else
    134                 prev->next = ptr->next;
    135 
    136         SNMP_FREE(entry);           /* XXX - release any other internal resources */
    137 }
    138 
    139 static void fill_diskinfotable_entry(struct DiskInfoTable_entry *entry) {
    140         int i;
    141 
    142         for (i = 0; i < MAX_DISK; i++) {
    143                 if (!strcmp(disk_info[i].filesystem, entry->Filesystem)) {
    144                         strncpy(entry->size, disk_info[i].size, strlen(disk_info[i].size));
    145                         //strcpy(entry->size, "444G");
    146                         strncpy(entry->used, disk_info[i].used, strlen(disk_info[i].used));
    147                         strncpy(entry->avail, disk_info[i].avail, strlen(disk_info[i].avail));
    148                         strncpy(entry->capacity, disk_info[i].capacity, strlen(disk_info[i].capacity));
    149                         strncpy(entry->mountedOn, disk_info[i].mountedOn, strlen(disk_info[i].mountedOn));
    150                 }
    151         }
    152 
    153 }
    154 
    155 static void read_data(void) {
    156         int i = 0;
    157         struct DiskInfoTable_entry *entry = NULL;
    158 
    159         if(DiskInfoTable_head == NULL){
    160                 for (i = 0; i < MAX_DISK; i++) {
    161                         DiskInfoTable_createEntry(disk_info[i].filesystem);
    162                 }
    163         }
    164 
    165         entry = DiskInfoTable_head;
    166 
    167         while (entry) {
    168                 fill_diskinfotable_entry(entry);
    169                 entry = entry->next;
    170         }
    171 
    172 
    173 }
    174 
    175 /*
    176  * Example iterator hook routines - using 'get_next' to do most of the work 
    177  */
    178         netsnmp_variable_list *
    179 DiskInfoTable_get_first_data_point(void **my_loop_context,
    180                 void **my_data_context,
    181                 netsnmp_variable_list * put_index_data,
    182                 netsnmp_iterator_info *mydata)
    183 {
    184         read_data();
    185         *my_loop_context = DiskInfoTable_head;
    186         *my_data_context = DiskInfoTable_head;
    187         return DiskInfoTable_get_next_data_point(my_loop_context,
    188                         my_data_context,
    189                         put_index_data, mydata);
    190 }
    191 
    192         netsnmp_variable_list *
    193 DiskInfoTable_get_next_data_point(void **my_loop_context,
    194                 void **my_data_context,
    195                 netsnmp_variable_list * put_index_data,
    196                 netsnmp_iterator_info *mydata)
    197 {
    198         struct DiskInfoTable_entry *entry =
    199                 (struct DiskInfoTable_entry *) *my_loop_context;
    200         netsnmp_variable_list *idx = put_index_data;
    201 
    202         if (entry) {
    203                 snmp_set_var_value(idx, (u_char *)entry->Filesystem,
    204                                 sizeof(entry->Filesystem));
    205                 idx = idx->next_variable;
    206                 *my_data_context = (void *) entry;
    207                 *my_loop_context = (void *) entry->next;
    208         } else {
    209                 return NULL;
    210         }
    211         return put_index_data;
    212 }
    213 
    214 
    215 /** handles requests for the DiskInfoTable table */
    216         int
    217 DiskInfoTable_handler(netsnmp_mib_handler *handler,
    218                 netsnmp_handler_registration *reginfo,
    219                 netsnmp_agent_request_info *reqinfo,
    220                 netsnmp_request_info *requests)
    221 {
    222 
    223         netsnmp_request_info *request;
    224         netsnmp_table_request_info *table_info;
    225         struct DiskInfoTable_entry *table_entry;
    226 
    227         switch (reqinfo->mode) {
    228                 /*
    229                  * Read-support (also covers GetNext requests)
    230                  */
    231                 case MODE_GET:
    232                         for (request = requests; request; request = request->next) {
    233                                 table_entry = (struct DiskInfoTable_entry *)
    234                                         netsnmp_extract_iterator_context(request);
    235                                 table_info = netsnmp_extract_table_info(request);
    236 
    237                                 switch (table_info->colnum) {
    238                                         case COLUMN_FILESYSTEM:
    239                                                 if (table_entry == NULL) {
    240                                                         netsnmp_set_request_error(reqinfo, request,
    241                                                                         SNMP_NOSUCHINSTANCE);
    242                                                         continue;
    243                                                 }
    244                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    245                                                                 (u_char *)table_entry->Filesystem,
    246                                                                 sizeof(table_entry->Filesystem));
    247                                                 break;
    248                                         case COLUMN_SIZE:
    249                                                 if (table_entry == NULL) {
    250                                                         netsnmp_set_request_error(reqinfo, request,
    251                                                                         SNMP_NOSUCHINSTANCE);
    252                                                         continue;
    253                                                 }
    254                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    255                                                                 (u_char *)table_entry->size,
    256                                                                 sizeof(table_entry->size));
    257                                                 break;
    258                                         case COLUMN_USED:
    259                                                 if (table_entry == NULL) {
    260                                                         netsnmp_set_request_error(reqinfo, request,
    261                                                                         SNMP_NOSUCHINSTANCE);
    262                                                         continue;
    263                                                 }
    264                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    265                                                                 (u_char *)table_entry->used,
    266                                                                 sizeof(table_entry->used));
    267                                                 break;
    268                                         case COLUMN_AVAIL:
    269                                                 if (table_entry == NULL) {
    270                                                         netsnmp_set_request_error(reqinfo, request,
    271                                                                         SNMP_NOSUCHINSTANCE);
    272                                                         continue;
    273                                                 }
    274                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    275                                                                 (u_char *)table_entry->avail,
    276                                                                 sizeof(table_entry->avail));
    277                                                 break;
    278                                         case COLUMN_CAPACITY:
    279                                                 if (table_entry == NULL) {
    280                                                         netsnmp_set_request_error(reqinfo, request,
    281                                                                         SNMP_NOSUCHINSTANCE);
    282                                                         continue;
    283                                                 }
    284                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    285                                                                 (u_char *)table_entry->capacity,
    286                                                                 sizeof(table_entry->capacity));
    287                                                 break;
    288                                         case COLUMN_MOUNTEDON:
    289                                                 if (table_entry == NULL) {
    290                                                         netsnmp_set_request_error(reqinfo, request,
    291                                                                         SNMP_NOSUCHINSTANCE);
    292                                                         continue;
    293                                                 }
    294                                                 snmp_set_var_typed_value(request->requestvb, ASN_OCTET_STR,
    295                                                                 (u_char *)table_entry->mountedOn,
    296                                                                 sizeof(table_entry->mountedOn));
    297                                                 break;
    298                                         default:
    299                                                 continue;
    300                                                 //netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE);
    301                                 }
    302                         }
    303                         break;
    304 
    305         }
    306         return SNMP_ERR_NOERROR;
    307 }
    Table code

    除了这些还需要有一个common.c把所有的代码连接到一起。

    1 #include "HostName.h"
    2 #include "DiskInfoTable.h"
    3 void init_diskcheck(void) {
    4     init_HostName();
    5     init_DiskInfoTable();
    6 }

    注:init_动态库名 和生成的动态库名字有联系,如果动态库名字不为 diskcheck.so net-snmp有可能无法识别。

    编译

    编译这块主要是利用net-snmp给的命令,直接给出Makefile好了。

     1 CC = gcc 
     2 
     3 DIR = HostName DiskInfoTable
     4 #DIR = HostName 
     5 
     6 vpath %.c ./
     7 vpath %.c $(DIR)
     8 
     9 INCLUDE = -I./
    10 INCLUDE += $(foreach x, $(DIR), -I./$(x))
    11 
    12 CFLAGS = -fPIC -shared -O3 
    13 CFLAGS += $(shell net-snmp-config --cflags)
    14 
    15 LDFLAGS = $(shell net-snmp-config --libs)
    16 
    17 SRC = common.c
    18 SRC += $(foreach x, $(DIR), $(x).c)
    19 OBJS = $(SRC:.c=.o)
    20 
    21 TARGET = diskcheck.so
    22 
    23 all:$(TARGET)
    24 
    25 $(TARGET):$(OBJS)
    26     $(CC) $^ -o $@ $(CFLAGS) $(LDFLAGS)
    27 
    28 $(OBJS):%.o:%.c
    29     $(CC) -c $^ -o $@ $(CFLAGS) $(INCLUDE)
    30 
    31 .PHONY:clean
    32 clean:
    33     rm *.o $(TARGET)

    把编译好的diskcheck.so拷贝到 /usr/lib (32位系统) /usr/lib64 (64位系统)中.

    修改配置文件

    1/etc/snmp/snmp.conf 中加上 mibs +MIB文件的名字(不带后缀)

    2/etc/snmp/snmpd.conf 中加上 

      dlmod 动态库名 动态库绝对路径 —— dlmod diskcheck /usr/lib/diskcheck.so

      view systemview .1

    Ps: /etc/snmp/snmpd.conf 中添加

    view    systemview    included   .1.3.6.1.4.1 

    有些系统在访问节点的时候有错误,例如在redhat as5.8 中有问题,而CentOS6.4中没问题【有可能是我的配置问题】。需要改成步骤二中的配置。

  • 相关阅读:
    [NOI2017]游戏
    [USACO09MAR]Cleaning Up
    [POI2010]Blocks
    [JSOI2011]分特产
    [POI2001]Peaceful Commission
    BZOJ4152 [AMPPZ2014]The Captain
    Luogu P3783 [SDOI2017]天才黑客
    Luogu P3645 [APIO2015]雅加达的摩天楼
    Luogu P1613 跑路
    AGC009E Eternal Average
  • 原文地址:https://www.cnblogs.com/ngnetboy/p/5205211.html
Copyright © 2011-2022 走看看