2 # -*- encoding: utf-8; py-indent-offset: 4 -*-
3 # +------------------------------------------------------------------+
4 # | ____ _ _ __ __ _ __ |
5 # | / ___| |__ ___ ___| | __ | \/ | |/ / |
6 # | | | | '_ \ / _ \/ __| |/ / | |\/| | ' / |
7 # | | |___| | | | __/ (__| < | | | | . \ |
8 # | \____|_| |_|\___|\___|_|\_\___|_| |_|_|\_\ |
10 # | Copyright Mathias Kettner 2014 mk@mathias-kettner.de |
11 # +------------------------------------------------------------------+
13 # This file is part of Check_MK.
14 # The official homepage is at http://mathias-kettner.de/check_mk.
16 # check_mk is free software; you can redistribute it and/or modify it
17 # under the terms of the GNU General Public License as published by
18 # the Free Software Foundation in version 2. check_mk is distributed
19 # in the hope that it will be useful, but WITHOUT ANY WARRANTY; with-
20 # out even the implied warranty of MERCHANTABILITY or FITNESS FOR A
21 # PARTICULAR PURPOSE. See the GNU General Public License for more de-
22 # tails. You should have received a copy of the GNU General Public
23 # License along with GNU Make; see the file COPYING. If not, write
24 # to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
25 # Boston, MA 02110-1301 USA.
27 # lookup tables for check implementation
28 # Taken from swFCPortPhyState
29 brocade_fcport_phystates
= {
46 # Taken from swFCPortOpStatus
47 brocade_fcport_opstates
= {
55 # Taken from swFCPortAdmStatus
56 brocade_fcport_admstates
= {
64 # Taken from swFCPortSpeed
65 brocade_fcport_speed
= {
77 # Taken from swNbBaudRate
79 "1": 0, # other (1) - None of the following.
80 "2": 0.155, # oneEighth (2) - 155 Mbaud.
81 "4": 0.266, # quarter (4) - 266 Mbaud.
82 "8": 0.532, # half (8) - 532 Mbaud.
83 "16": 1, # full (16) - 1 Gbaud.
84 "32": 2, # double (32) - 2 Gbaud.
85 "64": 4, # quadruple (64) - 4 Gbaud.
86 "128": 8, # octuple (128) - 8 Gbaud.
87 "256": 10, # decuple (256) - 10 Gbaud.
88 "512": 16, # sexdecuple (512) - 16 Gbaud
91 factory_settings
["brocade_fcport_default_levels"] = {
92 "rxcrcs": (3.0, 20.0), # allowed percentage of CRC errors
93 "rxencoutframes": (3.0, 20.0), # allowed percentage of Enc-OUT Frames
94 "rxencinframes": (3.0, 20.0), # allowed percentage of Enc-In Frames
95 "notxcredits": (3.0, 20.0), # allowed percentage of No Tx Credits
96 "c3discards": (3.0, 20.0), # allowed percentage of C3 discards
97 "assumed_speed": 2.0, # used if speed not available in SNMP data
101 def parse_brocade_fcport(info
):
102 if_info
, link_info
, speed_info
, if64_info
= info
105 isl_ports
= dict(link_info
)
107 for index
, entry
in enumerate(speed_info
):
108 # if-table and brocade-if-table do NOT have same length but
109 # http://community.brocade.com/t5/Fibre-Channel-SAN/SNMP-FC-port-speed/td-p/64980
110 # says that "1073741824" from if-table correlates with index 1 from
112 if entry
[0] == "1073741824":
113 speed_info
= [x
[1:] for x
in speed_info
[index
:]]
116 if len(if_info
) == len(speed_info
):
117 # extract the speed from IF-MIB::ifHighSpeed.
118 # unfortunately ports in the IF-MIB and the brocade MIB
119 # dont have a common index. We hope that at least
120 # the FC ports have the same sequence in both lists.
121 # here we go through ports of the IF-NIB, but consider only FC ports (type 56)
122 # and assume that the sequence number of the FC port here is the same
123 # as the sequence number in the borcade MIB (pindex = item_index)
124 if_table
= [x
+ y
if y
[0] == "56" else ["", x
[-2]] for x
, y
in zip(if_info
, speed_info
)]
126 if_table
= [x
+ ["", x
[-2]] for x
in if_info
]
129 for index
, phystate
, opstate
, admstate
, txwords
, rxwords
, txframes
, \
130 rxframes
, notxcredits
, rxcrcs
, rxencinframes
, rxencoutframes
, \
131 c3discards
, brocade_speed
, portname
, porttype
, ifspeed
in if_table
:
133 # Since FW v8.0.1b [rx/tx]words are no longer available
134 # Use 64bit counters if available
136 if len(if64_info
) > 0:
137 fcmgmt_portstats
= []
138 for oidend
, tx_elements
, rx_elements
, bbcredits_64
in if64_info
:
139 if index
== oidend
.split(".")[-1]:
141 binstring_to_int(''.join(map(chr, tx_elements
))) / 4,
142 binstring_to_int(''.join(map(chr, rx_elements
))) / 4,
143 binstring_to_int(''.join(map(chr, bbcredits_64
))),
147 txwords
= fcmgmt_portstats
[0]
148 rxwords
= fcmgmt_portstats
[1]
149 bbcredits
= fcmgmt_portstats
[2]
156 if index
in isl_ports
:
157 islspeed
= isl_speed
.get(isl_ports
[index
])
161 "phystate": int(phystate
),
162 "opstate": int(opstate
),
163 "admstate": int(admstate
),
164 "txwords": int(txwords
),
165 "rxwords": int(rxwords
),
166 "txframes": int(txframes
),
167 "rxframes": int(rxframes
),
168 "notxcredits": int(notxcredits
),
169 "rxcrcs": int(rxcrcs
),
170 "rxencinframes": int(rxencinframes
),
171 "rxencoutframes": int(rxencoutframes
),
172 "c3discards": int(c3discards
),
173 "brocade_speed": brocade_speed
,
174 "portname": portname
,
175 "porttype": porttype
,
176 "ifspeed": int(ifspeed
),
177 "is_isl": index
in isl_ports
,
178 "islspeed": islspeed
, # Might be None
179 "bbcredits": bbcredits
, # Might be None
186 def inventory_brocade_fcport(parsed
):
187 settings
= host_extra_conf_merged(host_name(), brocade_fcport_inventory
)
190 for if_entry
in parsed
:
191 admstate
= if_entry
["admstate"]
192 phystate
= if_entry
["phystate"]
193 opstate
= if_entry
["opstate"]
194 if brocade_fcport_inventory_this_port(
201 brocade_fcport_getitem(
202 number_of_ports
=len(parsed
),
203 index
=if_entry
["index"],
204 portname
=if_entry
["portname"],
205 is_isl
=if_entry
["is_isl"],
207 '{ "phystate": [%d], "opstate": [%d], "admstate": [%d] }' % (phystate
, opstate
,
213 def check_brocade_fcport(item
, params
, parsed
):
215 for if_entry
in parsed
:
216 if int(item
.split()[0]) + 1 == if_entry
["index"]:
217 found_entry
= if_entry
220 if found_entry
is None:
221 return 3, "No SNMP data found"
223 index
= found_entry
["index"]
224 txwords
= found_entry
["txwords"]
225 rxwords
= found_entry
["rxwords"]
226 txframes
= found_entry
["txframes"]
227 rxframes
= found_entry
["rxframes"]
228 notxcredits
= found_entry
["notxcredits"]
229 rxcrcs
= found_entry
["rxcrcs"]
230 rxencinframes
= found_entry
["rxencinframes"]
231 rxencoutframes
= found_entry
["rxencoutframes"]
232 c3discards
= found_entry
["c3discards"]
233 brocade_speed
= found_entry
["brocade_speed"]
234 is_isl
= found_entry
["is_isl"]
235 isl_speed
= found_entry
["islspeed"]
236 bbcredits
= found_entry
["bbcredits"]
237 speed
= found_entry
["ifspeed"]
239 this_time
= time
.time()
240 average
= params
.get("average") # range in minutes
241 bw_thresh
= params
.get("bw")
248 # Lookup port speed in ISL table for ISL ports (older switches do not provide this
249 # information in the normal table)
250 if is_isl
and isl_speed
is not None:
252 speedmsg
= ("ISL speed: %.0f Gbit/s" % isl_speed
)
255 if brocade_fcport_speed
.get(brocade_speed
, "unknown") in ["auto-Neg", "unknown"]:
257 # use actual speed of port if available
259 speedmsg
= "Speed: %g Gbit/s" % gbit
261 # let user specify assumed speed via check parameter, default is 2.0
262 gbit
= params
.get("assumed_speed")
263 speedmsg
= "Assumed speed: %g Gbit/s" % gbit
265 gbit
= float(brocade_fcport_speed
[brocade_speed
].replace("Gbit", ""))
266 speedmsg
= "%.0f Gbit/s" % gbit
268 output
.append(speedmsg
)
270 # convert gbit netto link-rate to Byte/s (8/10 enc)
271 wirespeed
= gbit
* 1000000000.0 * 0.8 / 8
272 in_bytes
= 4 * get_rate("brocade_fcport.rxwords.%s" % index
, this_time
, rxwords
)
273 out_bytes
= 4 * get_rate("brocade_fcport.txwords.%s" % index
, this_time
, txwords
)
276 # convert thresholds in percentage into MB/s
277 if bw_thresh
is None: # no levels
278 warn_bytes
, crit_bytes
= None, None
280 warn
, crit
= bw_thresh
281 if isinstance(warn
, float):
282 warn_bytes
= wirespeed
* warn
/ 100.0
284 warn_bytes
= warn
* 1048576.0
285 if isinstance(crit
, float):
286 crit_bytes
= wirespeed
* crit
/ 100.0
288 crit_bytes
= crit
* 1048576.0
290 for what
, value
in [("In", in_bytes
), ("Out", out_bytes
)]:
291 output
.append("%s: %s/s" % (what
, get_bytes_human_readable(value
)))
292 perfdata
.append((what
.lower(), value
, warn_bytes
, crit_bytes
, 0, wirespeed
))
293 # average turned on: use averaged traffic values instead of current ones
295 value
= get_average("brocade_fcport.%s.%s.avg" % (what
, item
), this_time
, value
,
297 output
.append("Average (%d min): %s/s" % (average
, get_bytes_human_readable(value
)))
298 perfaverages
.append(("%s_avg" % what
.lower(), value
, warn_bytes
, crit_bytes
, 0,
301 # handle levels for in/out
302 if crit_bytes
is not None and value
>= crit_bytes
:
304 output
.append(" >= %s/s(!!)" % (get_bytes_human_readable(crit_bytes
)))
305 elif warn_bytes
is not None and value
>= warn_bytes
:
306 summarystate
= max(1, summarystate
)
307 output
.append(" >= %s/s(!!)" % (get_bytes_human_readable(warn_bytes
)))
309 # put perfdata of averages after perfdata for in and out in order not to confuse the perfometer
310 perfdata
.extend(perfaverages
)
312 # R X F R A M E S & T X F R A M E S
313 # Put number of frames into performance data (honor averaging)
314 rxframes_rate
= get_rate("brocade_fcport.rxframes.%s" % index
, this_time
, rxframes
)
315 txframes_rate
= get_rate("brocade_fcport.txframes.%s" % index
, this_time
, txframes
)
316 for what
, value
in [("rxframes", rxframes_rate
), ("txframes", txframes_rate
)]:
317 perfdata
.append((what
, value
))
319 value
= get_average("brocade_fcport.%s.%s.avg" % (what
, item
), this_time
, value
,
321 perfdata
.append(("%s_avg" % what
, value
))
323 # E R R O R C O U N T E R S
324 # handle levels on error counters
325 for descr
, counter
, value
, ref
in [
326 ("CRC errors", "rxcrcs", rxcrcs
, rxframes_rate
),
327 ("ENC-Out", "rxencoutframes", rxencoutframes
, rxframes_rate
),
328 ("ENC-In", "rxencinframes", rxencinframes
, rxframes_rate
),
329 ("C3 discards", "c3discards", c3discards
, txframes_rate
),
330 ("No TX buffer credits", "notxcredits", notxcredits
, txframes_rate
),
332 per_sec
= get_rate("brocade_fcport.%s.%s" % (counter
, index
), this_time
, value
)
333 perfdata
.append((counter
, per_sec
))
335 # if averaging is on, compute average and apply levels to average
337 per_sec_avg
= get_average("brocade_fcport.%s.%s.avg" % \
338 (counter
, item
), this_time
, per_sec
, average
)
339 perfdata
.append(("%s_avg" % counter
, per_sec_avg
))
341 # compute error rate (errors in relation to number of frames) (from 0.0 to 1.0)
342 if ref
> 0 or per_sec
> 0:
343 rate
= per_sec
/ (ref
+ per_sec
)
346 text
= "%s: %.2f%%" % (descr
, rate
* 100.0)
348 # Honor averaging of error rate
350 rate
= get_average("brocade_fcport.%s.%s.avgrate" % (counter
, item
), this_time
, rate
,
352 text
+= ", Average: %.2f%%" % (rate
* 100.0)
354 error_percentage
= rate
* 100.0
355 warn
, crit
= params
.get(counter
, (None, None))
356 if crit
is not None and error_percentage
>= crit
:
360 elif warn
is not None and error_percentage
>= warn
:
361 summarystate
= max(1, summarystate
)
366 for dev_state
, state_key
, state_info
, warn_states
, state_map
in [
367 (found_entry
["phystate"], "phystate", "Physical", [1, 6], brocade_fcport_phystates
),
368 (found_entry
["opstate"], "opstate", "Operational", [1, 3], brocade_fcport_opstates
),
369 (found_entry
["admstate"], "admstate", "Administrative", [0, 1, 3],
370 brocade_fcport_admstates
),
373 if params
.get(state_key
) is not None and dev_state
!= params
[state_key
] \
374 and not (isinstance(params
[state_key
], list) and dev_state
in map(int, params
[state_key
])):
375 if dev_state
in warn_states
:
377 summarystate
= max(summarystate
, 1)
381 output
.append("%s: %s%s" % (state_info
, state_map
[dev_state
], errorflag
))
383 if bbcredits
is not None:
384 bbcredit_rate
= get_rate("brocade_fcport.bbcredit.%s" % (item
), this_time
, bbcredits
)
385 perfdata
.append(("fc_bbcredit_zero", bbcredit_rate
))
387 return (summarystate
, ', '.join(output
), perfdata
)
390 check_info
["brocade_fcport"] = {
391 'parse_function': parse_brocade_fcport
,
392 'check_function': check_brocade_fcport
,
393 'inventory_function': inventory_brocade_fcport
,
394 'service_description': 'Port %s',
395 'has_perfdata': True,
397 ( ".1.3.6.1.4.1.1588.2.1.1.1.6.2.1",[
399 3, # swFCPortPhyState
400 4, # swFCPortOpStatus
401 5, # swFCPortAdmStatus
402 11, # swFCPortTxWords
403 12, # swFCPortRxWords
404 13, # swFCPortTxFrames
405 14, # swFCPortRxFrames
406 20, # swFCPortNoTxCredits
408 21, # swFCPortRxEncInFrs
409 26, # swFCPortRxEncOutFrs
410 28, # swFCPortC3Discards
411 35, # swFCPortSpeed, deprecated from at least firmware version 7.2.1
412 36, # swFCPortName (not supported by all devices)
415 # Information about Inter-Switch-Links (contains baud rate of port)
416 ( ".1.3.6.1.4.1.1588.2.1.1.1.2.9.1", [
420 # new way to get port speed supported by Brocade
423 "2.2.1.3", # ifType, needed to extract fibre channel ifs only (type 56)
424 "31.1.1.1.15", # IF-MIB::ifHighSpeed
426 # Not every device supports that
427 (".1.3.6.1.3.94.4.5.1", [
429 BINARY("6"), # FCMGMT-MIB::connUnitPortStatCountTxElements
430 BINARY("7"), # FCMGMT-MIB::connUnitPortStatCountRxElements
431 BINARY("8"), # FCMGMT-MIB::connUnitPortStatCountBBCreditZero
434 'snmp_scan_function' : lambda oid
: oid(".1.3.6.1.2.1.1.2.0").startswith(".1.3.6.1.4.1.1588.2.1.1") \
435 and oid(".1.3.6.1.4.1.1588.2.1.1.1.6.2.1.*") is not None,
436 'includes' : [ 'brocade.include' ],
437 'group' : 'brocade_fcport',
438 'default_levels_variable' : 'brocade_fcport_default_levels',