【网络编程】——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中没问题【有可能是我的配置问题】。需要改成步骤二中的配置。

posted @ 2016-02-21 17:04  net小伙  阅读(3374)  评论(0编辑  收藏  举报