2 * snmpdelta.c - Monitor deltas of integer valued SNMP variables
5 /**********************************************************************
7 * Copyright 1996 by Carnegie Mellon University
11 * Permission to use, copy, modify, and distribute this software and its
12 * documentation for any purpose and without fee is hereby granted,
13 * provided that the above copyright notice appear in all copies and that
14 * both that copyright notice and this permission notice appear in
15 * supporting documentation, and that the name of CMU not be
16 * used in advertising or publicity pertaining to distribution of the
17 * software without specific, written prior permission.
19 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27 **********************************************************************/
29 #include <net-snmp/net-snmp-config.h>
42 #include <sys/types.h>
44 #include <netinet/in.h>
48 #if TIME_WITH_SYS_TIME
50 # include <sys/timeb.h>
52 # include <sys/time.h>
57 # include <sys/time.h>
63 #include <sys/select.h>
72 #include <arpa/inet.h>
75 #include <net-snmp/net-snmp-includes.h>
78 #define NETSNMP_DS_APP_DONT_FIX_PDUS 0
80 const char *SumFile
= "Sum";
83 * Information about the handled variables
92 struct counter64 c64value
;
101 struct varInfo varinfo
[128];
102 int current_name
= 0;
104 int deltat
= 0, timestamp
= 0, fileout
= 0, dosum
=
106 int keepSeconds
= 0, peaks
= 0;
108 int varbindsPerPacket
= 60;
110 void processFileArgs(char *fileName
);
116 "Usage: snmpdelta [-Cf] [-CF commandFile] [-Cl] [-CL SumFileName]\n\t[-Cs] [-Ck] [-Ct] [-CS] [-Cv vars/pkt] [-Cp period]\n\t[-CP peaks] ");
117 snmp_parse_args_usage(stderr
);
118 fprintf(stderr
, " oid [oid ...]\n");
119 snmp_parse_args_descriptions(stderr
);
120 fprintf(stderr
, "snmpdelta specific options\n");
121 fprintf(stderr
, " -Cf\t\tDon't fix errors and retry the request.\n");
122 fprintf(stderr
, " -Cl\t\twrite configuration to file\n");
123 fprintf(stderr
, " -CF config\tload configuration from file\n");
124 fprintf(stderr
, " -Cp period\tspecifies the poll period\n");
125 fprintf(stderr
, " -CP peaks\treporting period in poll periods\n");
126 fprintf(stderr
, " -Cv vars/pkt\tnumber of variables per packet\n");
127 fprintf(stderr
, " -Ck\t\tkeep seconds in output time\n");
128 fprintf(stderr
, " -Cm\t\tshow max values\n");
129 fprintf(stderr
, " -CS\t\tlog to a sum file\n");
130 fprintf(stderr
, " -Cs\t\tshow timestamps\n");
131 fprintf(stderr
, " -Ct\t\tget timing from agent\n");
132 fprintf(stderr
, " -CT\t\tprint output in tabular form\n");
133 fprintf(stderr
, " -CL sumfile\tspecifies the sum file name\n");
137 optProc(int argc
, char *const *argv
, int opt
)
142 switch ((opt
= *optarg
++)) {
144 netsnmp_ds_toggle_boolean(NETSNMP_DS_APPLICATION_ID
,
145 NETSNMP_DS_APP_DONT_FIX_PDUS
);
148 period
= atoi(argv
[optind
++]);
151 peaks
= atoi(argv
[optind
++]);
154 varbindsPerPacket
= atoi(argv
[optind
++]);
169 processFileArgs(argv
[optind
++]);
175 SumFile
= argv
[optind
++];
184 fprintf(stderr
, "Bad -C options: %c\n", opt
);
193 wait_for_peak_start(int period
, int peak
)
195 struct timeval m_time
, *tv
= &m_time
;
197 time_t SecondsAtNextHour
;
201 seconds
= period
* peak
;
204 * Find the current time
206 gettimeofday(tv
, (struct timezone
*) 0);
209 * Create a tm struct from it
211 memcpy(&tm
, localtime((time_t *) & tv
->tv_sec
), sizeof(tm
));
214 * Calculate the next hour
219 SecondsAtNextHour
= mktime(&tm
);
222 * Now figure out the amount of time to sleep
224 target
= (SecondsAtNextHour
- tv
->tv_sec
) % seconds
;
230 print_log(char *file
, char *message
)
234 fp
= fopen(file
, "a");
236 fprintf(stderr
, "Couldn't open %s\n", file
);
239 fprintf(fp
, "%s\n", message
);
244 sprint_descriptor(char *buffer
, struct varInfo
*vip
)
246 u_char
*buf
= NULL
, *cp
= NULL
;
247 size_t buf_len
= 0, out_len
= 0;
249 if (!sprint_realloc_objid(&buf
, &buf_len
, &out_len
, 1,
250 vip
->info_oid
, vip
->oidlen
)) {
257 for (cp
= buf
; *cp
; cp
++);
279 processFileArgs(char *fileName
)
282 char buf
[260] = { 0 }, *cp
;
283 int blank
, linenumber
= 0;
285 fp
= fopen(fileName
, "r");
288 while (fgets(buf
, sizeof(buf
), fp
)) {
290 if (strlen(buf
) > (sizeof(buf
) - 2)) {
291 fprintf(stderr
, "Line too long on line %d of %s\n",
292 linenumber
, fileName
);
298 for (cp
= buf
; *cp
; cp
++)
305 buf
[strlen(buf
) - 1] = 0;
306 varinfo
[current_name
++].name
= strdup(buf
);
313 wait_for_period(int period
)
315 struct timeval m_time
, *tv
= &m_time
;
318 static int target
= 0;
321 gettimeofday(tv
, (struct timezone
*) 0);
326 memcpy(&tm
, localtime((time_t *) & tv
->tv_sec
), sizeof(tm
));
330 nexthour
= mktime(&tm
);
332 target
= (nexthour
- tv
->tv_sec
) % period
;
335 target
+= tv
->tv_sec
;
338 tv
->tv_sec
= target
- tv
->tv_sec
;
339 if (tv
->tv_usec
!= 0) {
341 tv
->tv_usec
= 1000000 - tv
->tv_usec
;
343 if (tv
->tv_sec
< 0) {
345 * ran out of time, schedule immediately
352 count
= select(0, 0, 0, 0, tv
);
361 snmp_log_perror("select");
367 oid sysUpTimeOid
[9] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
368 size_t sysUpTimeLen
= 9;
371 main(int argc
, char *argv
[])
373 netsnmp_session session
, *ss
;
374 netsnmp_pdu
*pdu
, *response
;
375 netsnmp_variable_list
*vars
;
382 struct counter64 c64value
;
384 time_t last_time
= 0;
387 int sum
; /* what the heck is this for, its never used? */
388 char filename
[128] = { 0 };
391 char timestring
[64] = { 0 }, valueStr
[64] = {
394 char outstr
[256] = { 0 }, peakStr
[64] = {
397 int begin
, end
, last_end
;
401 switch (arg
= snmp_parse_args(argc
, argv
, &session
, "C:", &optProc
)) {
411 gateway
= session
.peername
;
413 for (; optind
< argc
; optind
++)
414 varinfo
[current_name
++].name
= argv
[optind
];
416 if (current_name
== 0) {
422 varinfo
[current_name
++].name
= 0;
428 * open an SNMP session
430 ss
= snmp_open(&session
);
433 * diagnose snmp_open errors with the input netsnmp_session pointer
435 snmp_sess_perror("snmpdelta", &session
);
440 if (tableForm
&& timestamp
) {
441 printf("%s", gateway
);
443 for (count
= 0; count
< current_name
; count
++) {
444 vip
= varinfo
+ count
;
446 vip
->oidlen
= MAX_OID_LEN
;
447 vip
->info_oid
= (oid
*) malloc(sizeof(oid
) * vip
->oidlen
);
448 if (snmp_parse_oid(vip
->name
, vip
->info_oid
, &vip
->oidlen
) ==
450 snmp_perror(vip
->name
);
454 sprint_descriptor(vip
->descriptor
, vip
);
456 printf("\t%s", vip
->descriptor
);
459 strcpy(vip
->descriptor
, SumFile
);
462 zeroU64(&vip
->c64value
);
466 vip
->peak_count
= -1;
468 vip
->peak_average
= 0;
472 wait_for_period(period
);
477 pdu
= snmp_pdu_create(SNMP_MSG_GET
);
480 snmp_add_null_var(pdu
, sysUpTimeOid
, sysUpTimeLen
);
482 if (end
== current_name
)
487 for (; count
< current_name
488 && count
< begin
+ varbindsPerPacket
- deltat
; count
++) {
489 if (varinfo
[count
].oidlen
)
490 snmp_add_null_var(pdu
, varinfo
[count
].info_oid
,
491 varinfo
[count
].oidlen
);
497 status
= snmp_synch_response(ss
, pdu
, &response
);
498 if (status
== STAT_SUCCESS
) {
499 if (response
->errstat
== SNMP_ERR_NOERROR
) {
501 gettimeofday(&tv
, (struct timezone
*) 0);
502 memcpy(&tm
, localtime((time_t *) & tv
.tv_sec
),
505 && (!peaks
|| ((period
* peaks
) % 60)))
507 sprintf(timestring
, " [%02d:%02d:%02d %d/%d]",
508 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
,
509 tm
.tm_mon
+ 1, tm
.tm_mday
);
511 sprintf(timestring
, " [%02d:%02d %d/%d]",
512 tm
.tm_hour
, tm
.tm_min
,
513 tm
.tm_mon
+ 1, tm
.tm_mday
);
516 vars
= response
->variables
;
519 fprintf(stderr
, "Missing variable in reply\n");
522 this_time
= *(vars
->val
.integer
);
524 vars
= vars
->next_variable
;
529 for (count
= begin
; count
< end
; count
++) {
530 vip
= varinfo
+ count
;
534 fprintf(stderr
, "Missing variable in reply\n");
537 vip
->type
= vars
->type
;
538 if (vars
->type
== ASN_COUNTER64
) {
539 u64Subtract(vars
->val
.counter64
,
540 &vip
->c64value
, &c64value
);
541 memcpy(&vip
->c64value
, vars
->val
.counter64
,
542 sizeof(struct counter64
));
544 value
= *(vars
->val
.integer
) - vip
->value
;
545 vip
->value
= *(vars
->val
.integer
);
547 vars
= vars
->next_variable
;
552 delta_time
= this_time
- vip
->time
;
555 last_time
= vip
->time
;
556 vip
->time
= this_time
;
560 if (vip
->oidlen
&& vip
->type
!= ASN_COUNTER64
) {
565 if (count
== begin
) {
566 sprintf(outstr
, "%s", timestring
+ 1);
569 sprintf(outstr
, "%s %s", timestring
,
573 if (deltat
|| tableForm
) {
574 if (vip
->type
== ASN_COUNTER64
) {
576 "time delta and table form not supported for counter64s\n");
580 ((float) value
* 100) / delta_time
;
582 sprintf(valueStr
, "\t%.2f", printvalue
);
584 sprintf(valueStr
, " /sec: %.2f",
588 printvalue
= (float) value
;
589 sprintf(valueStr
, " /%d sec: ", period
);
590 if (vip
->type
== ASN_COUNTER64
)
591 printU64(valueStr
+ strlen(valueStr
),
594 sprintf(valueStr
+ strlen(valueStr
), "%u",
599 strcat(outstr
, valueStr
);
602 if (vip
->peak_count
== -1) {
603 if (wait_for_peak_start(period
, peaks
) == 0)
606 vip
->peak_average
+= printvalue
;
607 if (vip
->peak
< printvalue
)
608 vip
->peak
= printvalue
;
609 if (++vip
->peak_count
== peaks
) {
612 " /sec: %.2f (%d sec Peak: %.2f)",
614 vip
->peak_count
, period
,
618 " /%d sec: %.0f (%d sec Peak: %.0f)",
621 vip
->peak_count
, period
,
623 vip
->peak_average
= 0;
627 strcat(outstr
, peakStr
);
633 if (printvalue
> vip
->max
) {
634 vip
->max
= printvalue
;
637 sprintf(maxStr
, " (Max: %.2f)", vip
->max
);
639 sprintf(maxStr
, " (Max: %.0f)", vip
->max
);
640 strcat(outstr
, maxStr
);
645 sprintf(filename
, "%s-%s", gateway
,
647 print_log(filename
, outstr
+ 1);
650 printf("%s", outstr
);
652 printf("%s\n", outstr
+ 1);
657 if (end
== last_end
&& tableForm
)
660 if (response
->errstat
== SNMP_ERR_TOOBIG
) {
661 if (response
->errindex
<= varbindsPerPacket
662 && response
->errindex
> 0) {
663 varbindsPerPacket
= response
->errindex
- 1;
665 if (varbindsPerPacket
> 30)
666 varbindsPerPacket
-= 5;
670 if (varbindsPerPacket
<= 0) {
676 } else if (response
->errindex
!= 0) {
677 fprintf(stderr
, "Failed object: ");
678 for (count
= 1, vars
= response
->variables
;
679 vars
&& count
!= response
->errindex
;
680 vars
= vars
->next_variable
, count
++);
682 fprint_objid(stderr
, vars
->name
,
684 fprintf(stderr
, "\n");
686 * Don't exit when OIDs from file are not found on agent
691 fprintf(stderr
, "Error in packet: %s\n",
692 snmp_errstring(response
->errstat
));
698 * retry if the errored variable was successfully removed
700 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID
,
701 NETSNMP_DS_APP_DONT_FIX_PDUS
)) {
702 pdu
= snmp_fix_pdu(response
, SNMP_MSG_GET
);
703 snmp_free_pdu(response
);
710 } else if (status
== STAT_TIMEOUT
) {
711 fprintf(stderr
, "Timeout: No Response from %s\n", gateway
);
715 } else { /* status == STAT_ERROR */
716 snmp_sess_perror("snmpdelta", ss
);
723 snmp_free_pdu(response
);
724 if (end
== current_name
) {
725 wait_for_period(period
);