1 /*
2  * File:      check_cisco_if_load.c
3  * Copyright: (c) 2006 by Peter Gritsch
4  * Email:     s4nag@no-where.at
5  *
6  * This file is part of SNMP4Nagios.
7  *
8  * SNMP4Nagios is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or (at
11  * your option) any later version.
12  *
13  * SNMP4Nagios is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with SNMP4Nagios; if not, write to the
20  *
21  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22  * MA 02110-1301, USA
23  */
24 
25 /*
26  * This is not a good example. It uses just one column and is therefor
27  * somewhat different (and simplier)! There is but one feature you might
28  * want to check: How to get a value from an entirely different table which
29  * uses the same indices.
30  */
31 
32 #if HAVE_CONFIG_H
33 #include <config.h>
34 #endif
35 
36 #include "errno.h"
37 #include "globals.h"
38 #include "nagiosif.h"
39 #if(WITH_RRD)
40 #include "rrdif.h"
41 #endif /* WITH_RRD */
42 #include "snmpif.h"
43 #include "syslogif.h"
44 #include "strutils.h"
45 #include "utilities.h"
46 
47 /* data type for storing scan results */
48 typedef struct
49 {
50     int index;   /* interface index */
51     char* descr; /* interface description */
52 } tScanRes;
53 
54 /* data type for storing data */
55 typedef struct
56 {
57     int  load;
58 } tDataSet;
59 
60 /* global input variables */
61 int warn;
62 int crit;
63 int isWarnSet  = FALSE;
64 int isCritSet  = FALSE;
65 
66 /*
67  * SNMP base OID
68  * OLD-CISCO-INTERFACES-MIB::locIfLoad.IDX  = .1.3.6.1.4.1.9.2.2.1.1.24.IDX
69  *
70  * This OID is needed to get the interface names:
71  * IF-MIB::ifDescr.IDX                      = .1.3.6.1.2.1.2.2.1.2.IDX
72  */
73 oid baseOID[] = { 1, 3, 6, 1, 4, 1, 9, 2, 2, 1, 1, 24 };
74 size_t baseOIDLen = 12;
75 
76 /* scan results */
77 tScanRes* scanRes = NULL;
78 int scanResLen = 0;
79 
80 /* results of the SNMP queries */
81 tDataSet v;
82 
83 
SetGlobals()84 void SetGlobals ()
85 {
86     /* progName is set by ReadArgs() */
87     srvName = "check_cisco_if_load";
88     progVersion = "0.1";
89     helpIndexP = "-i INDEX -w WARN -c CRIT";
90     helpThresP = NULL;
91     helpPurpose = "Checks the load of a network interface.";
92     /* community is set by ReadArgs() */
93     /* commFile is set by ReadArgs() */
94 #if(WITH_RRD)
95     rrdStep = 1 * 60;
96     rrdHBeat = 3 * 60;
97 #endif /* WITH_RRD */
98     supportsPerfLog = TRUE;
99     hasIndexParam = TRUE;
100     hasAddInfParam = TRUE;
101 }
102 
HelpSpecificParams()103 void HelpSpecificParams ()
104 {
105     printf (
106     "-i, --index INTEGER\n"
107     "    Index of the network interface which should be checked.\n"
108     "\n"
109     "-w, --warning INTEGER\n"
110     "    Interface load at which a warning is generated (255 = 100%%)\n"
111     "\n"
112     "-c, --critical INTEGER\n"
113     "    Interface load at which a critical is generated (255 = 100%%)\n"
114     "\n"
115     );
116 }
117 
HelpExplain()118 void HelpExplain ()
119 {
120     printf (
121     "Generates a warning/critical if the interface load is above the\n"
122     " respective level.\n"
123     "\n"
124     );
125 }
126 
HelpPerformanceData()127 void HelpPerformanceData ()
128 {
129     printf (
130     "Native performance data is provided in the format:\n"
131     "<addInf>;<load>\n"
132     "where\n"
133     "    addInf ... additional information.\n"
134     "    load   ... interface load (0 to 255)\n"
135     "\n"
136     );
137     printf (
138     "Nagios Plugins compatible performance data is provided in the format:\n"
139     "'load'=<load>;<warn>;<crit>;0;255\n"
140     "\n"
141     );
142 }
143 
ChkOptSpecificParams(int argc,char ** argv,int * i)144 int ChkOptSpecificParams ( int argc, char** argv, int* i )
145 {
146     int ret = TRUE;
147 
148     if (        !strcmp ( argv [(*i)], "-w" )
149             ||  !strcmp ( argv [(*i)], "--warning" ) )
150     {
151         isWarnSet = TRUE;
152         (*i)++;
153         if ( (*i) < argc )
154         {
155             char *tail = argv [(*i)];
156 
157             errno = 0;
158             warn = strtol ( argv [(*i)++], &tail, 0 );
159             if ( errno || (*tail) ) Usage ( "Invalid 'warn' parameter" );
160         }
161         else Usage ( "Missing 'warn' parameter(s)" );
162     } else if ( !strcmp ( argv [(*i)], "-c" )
163             ||  !strcmp ( argv [(*i)], "--critical" ) )
164     {
165         isCritSet = TRUE;
166         (*i)++;
167         if ( (*i) < argc )
168         {
169             char *tail = argv [(*i)];
170 
171             errno = 0;
172             crit = strtol ( argv [(*i)++], &tail, 0 );
173             if ( errno || (*tail) ) Usage ( "Invalid 'crit' parameter" );
174         }
175         else Usage ( "Missing 'crit' parameter(s)" );
176     } else ret = FALSE;
177     return ( ret );
178 }
179 
ScanResGetName(int aIdx)180 char* ScanResGetName ( int aIdx )
181 {
182     struct snmp_session sess1;
183     struct snmp_session* sess2;
184     oid o_descr [] = { 1, 3, 6, 1, 2, 1, 2, 2, 1, 2, aIdx };
185     size_t oidLen = 11;
186     char* ret;
187 
188     ConfigureSession1 ( &sess1 );
189     sess2 = snmp_open ( &sess1 );
190     if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
191     ret = ReadString ( sess2, o_descr, oidLen );
192     free ( sess1.peername );
193     free ( sess1.community );
194     return ( ret );
195 }
196 
SnmpWalkHandleVariable(netsnmp_variable_list * aVar)197 void SnmpWalkHandleVariable ( netsnmp_variable_list* aVar )
198 {
199     if ( aVar->name_length == 13 )
200     {
201         if ( OidCmp ( aVar->name, baseOID, baseOIDLen ) == 0 )
202         {
203             int index;
204 
205             index = scanResLen;
206             scanResLen++;
207             scanRes = realloc ( scanRes, sizeof ( tScanRes ) * scanResLen );
208             if ( scanRes == NULL ) ErrorMalloc ();
209             scanRes [index].index = aVar->name [12];
210             scanRes [index].descr = ScanResGetName ( aVar->name [12] );
211         } else Log ( LOG_CRIT, "Unexpected OID while scanning services" );
212     } else Log ( LOG_CRIT, "Wrong length while scanning services" );
213 }
214 
ScanServices()215 int ScanServices ()
216 {
217     int i;
218     int retVal = STATE_UNKNOWN;
219 
220     SnmpWalk ( baseOID, baseOIDLen );
221     for ( i = 0; i < scanResLen; i++ )
222     {
223         retVal = STATE_OK;
224         printf ( "OK index: %i ; descr: %s\n",
225                     scanRes [i].index, scanRes [i].descr );
226     }
227     if ( retVal == STATE_UNKNOWN ) printf ( "FAILED\n" );
228     return retVal;
229 }
230 
ReadVals()231 void ReadVals ()
232 {
233     struct snmp_session sess1;
234     struct snmp_session* sess2;
235     oid o_load [13];
236     size_t oidLen;
237 
238     OidCpy ( o_load, &oidLen, baseOID, &baseOIDLen );
239     o_load [12] = idx;
240     oidLen = 13;
241     ConfigureSession1 ( &sess1 );
242     sess2 = snmp_open ( &sess1 );
243     if ( sess2 == NULL ) Error ( LOG_ERR, "Could not open session!" );
244     v.load  = ReadInteger   ( sess2, o_load, oidLen );
245     free ( sess1.peername );
246     free ( sess1.community );
247     snmp_close_sessions ();
248 }
249 
250 #if(WITH_RRD)
CreateDataFile(const char * aRRDFPath)251 void CreateDataFile ( const char* aRRDFPath )
252 {
253     int i = 0;
254     char* params[1024]; /* Now that should be enough! */
255     params [i++] = StrDup ( "JUNK" );
256     params [i++] = StrDup ( aRRDFPath );
257     params [i++] = StrDup ( "-s" );
258     params [i++] = IntToStr ( rrdStep );
259     params [i++] = CreateDSStr ( "load",  GAUGE, rrdHBeat, "0", "U" );
260     params [i++] = RRA_MAX_7H_1M;
261     params [i++] = RRA_AVG_7H_1M;
262     params [i++] = RRA_MAX_25H_5M;
263     params [i++] = RRA_AVG_25H_5M;
264     params [i++] = RRA_MAX_8D_15M;
265     params [i++] = RRA_AVG_8D_15M;
266     params [i++] = RRA_MAX_32D_1H;
267     params [i++] = RRA_AVG_32D_1H;
268     params [i++] = RRA_MAX_367D_4H;
269     params [i++] = RRA_AVG_367D_4H;
270     RRDCreate ( i, params, aRRDFPath );
271     while ( i > 0 ) free ( params [--i] );
272 }
273 
ParseData(const char * aData)274 void ParseData ( const char* aData )
275 {
276     int chk;
277     char buf[1024];
278 
279     chk = sscanf ( aData, "%1023s;%u", buf, &(v.load) );
280     if ( chk != 2 )
281     {
282         char msg[1024];
283         snprintf ( msg, 1024,
284                 "Could not parse performance data: %s.\n", aData );
285         Error ( LOG_ERR, msg );
286     }
287     addInf = StrDup ( buf );
288 }
289 
WriteData(const char * aRRDFPath)290 void WriteData ( const char* aRRDFPath )
291 {
292     int i = 0;
293     char* params[1024]; /* Now that should be enough! */
294     char* ts     = UIntToStr   ( GetTimestamp () );
295     char* load   = UIntToStr   ( v.load );
296 
297     params [i++] = StrDup ( "JUNK" );
298     params [i++] = StrDup ( aRRDFPath );
299     params [i++] = StrDup ( "-t" );
300     params [i++] = StrDup ( "load" );
301     params [i++] = StrConcat ( 3, ts, ":", load );
302     RRDUpdate ( i, params, aRRDFPath );
303     while ( i > 0 ) free ( params [--i] );
304     free ( load );
305     free ( ts );
306 }
307 
PlotDataLoad(tFN * aFN,int aTiming,int aNow)308 void PlotDataLoad ( tFN* aFN, int aTiming, int aNow )
309 {
310     tPP* pp = PPInit ();
311     int i = 0;
312     char* title = NULL;
313     char* vLabel = "[%]";
314     char* params[1024]; /* Now that should be enough! */
315 
316     FNSetPNGData ( aFN, NULL, aTiming );
317     PPAddPlot ( pp, "interface load",  "%", FALSE );
318     title = StrConcat ( 4, hostName, " interface ", addInf, " load" );
319     i = PlotStdParams ( params, aFN, title, vLabel,
320             aTiming, aNow - rrdHBeat, 1000, PLOT_SI_NONE, 0, 100, FALSE );
321     params [i++] = CreateDEF ( "loadMR", aFN, "load", MAX );
322     params [i++] = CreateDEF ( "loadAR", aFN, "load", AVG );
323     params [i++] = StrDup ( "CDEF:loadM=loadMR,255,/,100,*" );
324     params [i++] = StrDup ( "CDEF:loadA=loadAR,255,/,100,*" );
325     params [i++] = CreatePlot ( PLOT_AREA,  "loadM", C_THRU_MAX, pp, 0, MAX, FALSE );
326     params [i++] = CreatePlot ( PLOT_LINE2, "loadA", C_THRU_AVG, pp, 0, AVG, TRUE );
327     i = PlotPrintParams ( i, params, pp, 0, "loadA", "loadA", "loadM", "loadM", "%5.1lf" );
328     RRDGraph ( i, params, aFN, pp );
329     while ( i > 0 ) free ( params [--i] );
330     free ( title );
331     PPDone ( pp );
332     FNUnsetPNGData ( aFN );
333 }
334 
PlotPerfData()335 void PlotPerfData ()
336 {
337     int now = time ( NULL );
338     tFN* fn = FNInit ();
339 
340     PlotDataLoad ( fn, PLOT_6H_1M,   now );
341     PlotDataLoad ( fn, PLOT_24H_5M,  now );
342     PlotDataLoad ( fn, PLOT_7D_15M,  now );
343     PlotDataLoad ( fn, PLOT_31D_60M, now );
344     PlotDataLoad ( fn, PLOT_366D_4H, now );
345     FNDone ( fn );
346 }
347 #endif /* WITH_RRD */
348 
CheckData()349 int CheckData ()
350 {
351     int retVal = STATE_OK;
352 
353     ReadVals ();
354     if ( warn < v.load ) retVal = MAXIMUM ( retVal, STATE_WARNING );
355     if ( crit < v.load ) retVal = MAXIMUM ( retVal, STATE_CRITICAL );
356     PrintExit ( retVal );
357     printf ( " - interface load: %i", v.load );
358     if ( npPerfData )
359     {
360         printf ( "|'interface load'=%i;%i;%i;0;255\n", v.load, warn, crit );
361     }
362     else
363     {
364         printf ( "|%s;%i\n", addInf, v.load );
365     }
366     return ( retVal );
367 }
368 
main(int argc,char ** argv)369 int main ( int argc, char** argv )
370 {
371     int retVal = STATE_OK;
372 
373     SetGlobals ();
374     ReadArgs ( argc, argv );
375     if ( checkData )
376     {
377         if ( !isWarnSet ) Usage ( "Missing 'warn' parameters" );
378         if ( !isCritSet ) Usage ( "Missing 'crit' parameters" );
379     }
380     if ( scanServices ) retVal = ScanServices ();
381     else
382     {
383         if ( checkData ) retVal = CheckData ();
384 #if(WITH_RRD)
385         if ( logPerfData ) LogPerfData ();
386         if ( plotPerfData ) PlotPerfData ();
387 #endif /* WITH_RRD */
388     }
389     if ( hostName != NULL ) free ( hostName );
390     if ( hostAddr != NULL ) free ( hostAddr );
391     if ( progName != NULL ) free ( progName );
392     return ( retVal );
393 }
394