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