#!/usr/bin/python # -*- encoding: utf-8; py-indent-offset: 4 -*- # # Cisco BGP Peer # # Author: thl-cmk[at]outlook[dot]com / thl-cmk.hopto.org # Date : 2017-12-26 # # Monitor status of Cisco BGP Peer (IPv4 and IPv6) # # 24.05.2018: changed counters to 1/s # 25.05.2018: a lot of code cleanup # packet name changed from cisco_bgp to cisco_bgp_peer # added support of more then one address family per peer # (changed item from remoteip to remoteip+familyname, rewrite of parer, inventory and check function) # 27.05.2018: changed scan function from '.1.3.6.1.4.1.9.9.187.1.2.7.1.3.* to sysdecr contains cisco # 28.05.2018: changed wato, added peer alias, state if not found, infotext values # 29.05.2018: fixed longoutpout (removed not configured) # 02.11.2018: modified scanfunction (from "find 'cisco' =-1" to "'cisco' in OID" # 02.18.2019: added fix for empty values ("" instead of "0") sugested by Laurent Barbier (lbarbier[at]arkane-studios[dot]com) # 24.02.2020: added workaround for missing cbgpPeer2AddrFamily (example L2VPN EVPN peers, Fix for jonale82[at]gmail[dot]com) # 02.03.2020: changed handling of perfdata, add only data the are really there (not None, instead of setting them to 0) # 04.06.2020: code cleanup --> changed isdigit test to try/except loop, changed peer.get test to try/except loop # 21.07.2021: fixed parse section for missing oid_end # # snmpwalk sample # # CISCO-BGP4-MIB::cbgpPeer2AddrFamilyEntry # # OMD[mysite]:~$ snmpwalk -ObentU -v2c -c simulant 1.3.6.1.4.1.9.9.187.1.2.7 # .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.62.214.127.57.1.1 = STRING: "IPv4 Unicast" # .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.217.119.208.1.1.1 = STRING: "IPv4 Unicast" # .1.3.6.1.4.1.9.9.187.1.2.7.1.3.1.4.217.119.208.33.1.1 = STRING: "IPv4 Unicast" # .1.3.6.1.4.1.9.9.187.1.2.7.1.3.2.16.32.1.20.56.7.0.0.39.0.0.0.0.0.0.0.1.2.1 = STRING: "IPv6 Unicast" # .1.3.6.1.4.1.9.9.187.1.2.7.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = STRING: "IPv6 Unicast" # # CISCO-BGP4-MIB::CbgpPeer2Entry (IPv4) # # OMD[mysite]:~$ snmpwalk -ObentU -v2c -c simulant 1.3.6.1.4.1.9.9.187.1.2.5.1| grep 62.214.127.57 # .1.3.6.1.4.1.9.9.187.1.2.5.1.3.1.4.62.214.127.57 = INTEGER: 6 # .1.3.6.1.4.1.9.9.187.1.2.5.1.4.1.4.62.214.127.57 = INTEGER: 2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.5.1.4.62.214.127.57 = INTEGER: 4 # .1.3.6.1.4.1.9.9.187.1.2.5.1.6.1.4.62.214.127.57 = Hex-STRING: 3E D6 7F 3A # .1.3.6.1.4.1.9.9.187.1.2.5.1.7.1.4.62.214.127.57 = Gauge32: 29418 # .1.3.6.1.4.1.9.9.187.1.2.5.1.8.1.4.62.214.127.57 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.5.1.9.1.4.62.214.127.57 = IpAddress: 217.119.208.2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.10.1.4.62.214.127.57 = Gauge32: 179 # .1.3.6.1.4.1.9.9.187.1.2.5.1.11.1.4.62.214.127.57 = Gauge32: 8881 # .1.3.6.1.4.1.9.9.187.1.2.5.1.12.1.4.62.214.127.57 = IpAddress: 62.214.127.57 # .1.3.6.1.4.1.9.9.187.1.2.5.1.13.1.4.62.214.127.57 = Counter32: 18 # .1.3.6.1.4.1.9.9.187.1.2.5.1.14.1.4.62.214.127.57 = Counter32: 2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.15.1.4.62.214.127.57 = Counter32: 205 # .1.3.6.1.4.1.9.9.187.1.2.5.1.16.1.4.62.214.127.57 = Counter32: 195 # .1.3.6.1.4.1.9.9.187.1.2.5.1.17.1.4.62.214.127.57 = Hex-STRING: 00 00 # .1.3.6.1.4.1.9.9.187.1.2.5.1.18.1.4.62.214.127.57 = Counter32: 1 # .1.3.6.1.4.1.9.9.187.1.2.5.1.19.1.4.62.214.127.57 = Gauge32: 10446 # .1.3.6.1.4.1.9.9.187.1.2.5.1.20.1.4.62.214.127.57 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.21.1.4.62.214.127.57 = INTEGER: 180 # .1.3.6.1.4.1.9.9.187.1.2.5.1.22.1.4.62.214.127.57 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.23.1.4.62.214.127.57 = INTEGER: 180 # .1.3.6.1.4.1.9.9.187.1.2.5.1.24.1.4.62.214.127.57 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.25.1.4.62.214.127.57 = INTEGER: 30 # .1.3.6.1.4.1.9.9.187.1.2.5.1.26.1.4.62.214.127.57 = INTEGER: 30 # .1.3.6.1.4.1.9.9.187.1.2.5.1.27.1.4.62.214.127.57 = Gauge32: 5824 # .1.3.6.1.4.1.9.9.187.1.2.5.1.28.1.4.62.214.127.57 = "" # .1.3.6.1.4.1.9.9.187.1.2.5.1.29.1.4.62.214.127.57 = INTEGER: 5 # # # CISCO-BGP4-MIB::CbgpPeer2Entry (IPv6) # # OMD[mysite]:~$ snmpwalk -ObentU -v2c -c simulant 1.3.6.1.4.1.9.9.187.1.2.5.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 # .1.3.6.1.4.1.9.9.187.1.2.5.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 6 # .1.3.6.1.4.1.9.9.187.1.2.5.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 4 # .1.3.6.1.4.1.9.9.187.1.2.5.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Hex-STRING: 2A 05 57 C0 00 00 FF FF 00 00 00 00 00 00 00 11 # .1.3.6.1.4.1.9.9.187.1.2.5.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 179 # .1.3.6.1.4.1.9.9.187.1.2.5.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.5.1.9.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = IpAddress: 217.119.208.2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.10.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 35062 # .1.3.6.1.4.1.9.9.187.1.2.5.1.11.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 31259 # .1.3.6.1.4.1.9.9.187.1.2.5.1.12.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = IpAddress: 217.119.208.1 # .1.3.6.1.4.1.9.9.187.1.2.5.1.13.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 5 # .1.3.6.1.4.1.9.9.187.1.2.5.1.14.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 6 # .1.3.6.1.4.1.9.9.187.1.2.5.1.15.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 157 # .1.3.6.1.4.1.9.9.187.1.2.5.1.16.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 161 # .1.3.6.1.4.1.9.9.187.1.2.5.1.17.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Hex-STRING: 06 04 # .1.3.6.1.4.1.9.9.187.1.2.5.1.18.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Counter32: 2 # .1.3.6.1.4.1.9.9.187.1.2.5.1.19.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 8430 # .1.3.6.1.4.1.9.9.187.1.2.5.1.20.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.21.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 180 # .1.3.6.1.4.1.9.9.187.1.2.5.1.22.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.23.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 180 # .1.3.6.1.4.1.9.9.187.1.2.5.1.24.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 60 # .1.3.6.1.4.1.9.9.187.1.2.5.1.25.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 0 # .1.3.6.1.4.1.9.9.187.1.2.5.1.26.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 0 # .1.3.6.1.4.1.9.9.187.1.2.5.1.27.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = Gauge32: 1494 # .1.3.6.1.4.1.9.9.187.1.2.5.1.28.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = STRING: "Administrative Reset" # .1.3.6.1.4.1.9.9.187.1.2.5.1.29.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 = INTEGER: 5 # # # CISCO-BGP4-MIB::cbgpPeer2AddrFamilyPrefixEntry (IPv4) # # OMD[mysite]:~$ snmpwalk -ObentU -v2c -c simulant 1.3.6.1.4.1.9.9.187.1.2.8.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 # .1.3.6.1.4.1.9.9.187.1.2.8.1.1.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Counter32: 2 # .1.3.6.1.4.1.9.9.187.1.2.8.1.2.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.8.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 100000 # .1.3.6.1.4.1.9.9.187.1.2.8.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 85 # .1.3.6.1.4.1.9.9.187.1.2.8.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 80 # .1.3.6.1.4.1.9.9.187.1.2.8.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 10 # .1.3.6.1.4.1.9.9.187.1.2.8.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.8.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # # # CISCO-BGP4-MIB::cbgpPeer2AddrFamilyPrefixEntry (IPv6) # # OMD[mysite]:~$ snmpwalk -ObentU -v2c -c simulant 1.3.6.1.4.1.9.9.187.1.2.8.1| grep 16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16 # .1.3.6.1.4.1.9.9.187.1.2.8.1.1.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Counter32: 2 # .1.3.6.1.4.1.9.9.187.1.2.8.1.2.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.8.1.3.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 100000 # .1.3.6.1.4.1.9.9.187.1.2.8.1.4.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 85 # .1.3.6.1.4.1.9.9.187.1.2.8.1.5.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 80 # .1.3.6.1.4.1.9.9.187.1.2.8.1.6.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 10 # .1.3.6.1.4.1.9.9.187.1.2.8.1.7.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # .1.3.6.1.4.1.9.9.187.1.2.8.1.8.2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.16.2.1 = Gauge32: 0 # # # sample info # # [ # [ # ['1.4.77.235.182.229', '6', '2', 'M\xeb\xb6\xe6', '0', '217.119.208.1', '21413', '77.235.182.229', '1', '3', '48', # '53', '\x04\x00', '8', '2581', '2581', 'hold time expired', '5'], # ['1.4.217.119.208.2', '6', '2', '\xd9w\xd0\x01', '0', '217.119.208.1', '31259', '217.119.208.2', '11', '23', '168', # '170', '\x06\x04', '3', '8380', '5774', 'Administrative Reset', '5'], # ['1.4.217.119.208.34', '6', '2', '\xd9w\xd0!', '0', '217.119.208.1', '31259', '217.119.208.2', '11', '23', '168', # '170', '\x06\x04', '3', '8377', '5774', 'Administrative Reset', '5'], # ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1', '6', '2', '*\x00\x1c\xa0\x10\x00\x015\x00\x00\x00\x00\x00\x00\x00\x02', # '0', '217.119.208.1', '21413', '77.235.182.229', '0', '4', '108', '121', '\x06\x04', '6', '6295', '0', # 'Administrative Reset', '5'], # ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17', '6', '2', '*\x05W\xc0\x00\x00\xff\xff\x00\x00\x00\x00\x00\x00\x00\x10', # '0', '217.119.208.1', '31259', '217.119.208.2', '6', '5', '160', '157', '\x06\x04', '2', '8380', '1409', # 'Administrative Reset', '5'] # ], # [ # ['1.4.77.235.182.229.1.1', 'IPv4 Unicast', '1', '0', '', '', '', '6', '0', '0'], # ['1.4.217.119.208.2.1.1', 'IPv4 Unicast', '4', '0', '', '', '', '17', '0', '10'], # ['1.4.217.119.208.34.1.1', 'IPv4 Unicast', '4', '0', '', '', '', '17', '0', '10'], # ['2.16.42.0.28.160.16.0.1.53.0.0.0.0.0.0.0.1.2.1', 'IPv6 Unicast', '0', '0', '100000', '85', '80', '6', '0', '0'], # ['2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1', 'IPv6 Unicast', '2', '0', '100000', '85', '80', '8', '0', '0'] # ] # ] # # # factory_settings['cisco_bgp_peer_defaults'] = { 'minuptime': 86400, 'useaslocalas': 0, 'htmloutput': False, 'infotext_values': [], 'peer_list': [], } ########################################################################### # # DATA Parser function # ########################################################################### def parse_cisco_bgp_peer(info): def bgp_render_ipv4_address(bytestring): return ".".join(["%s" % ord(m) for m in bytestring]) def bgp_shorten_ipv6_adress(address): address = address.split(':') span = 2 address = [''.join(address[i:i + span]) for i in range(0, len(address), span)] for m in range(0, len(address)): address[m] = re.sub(r'^0{1,3}', r'', address[m]) address = ':'.join(address) zeros = ':0:0:0:0:0:0:' while not zeros == '': if zeros in address: address = re.sub(r'%s' % zeros, r'::', address) zeros = '' else: zeros = zeros[:-2] return address def bgp_render_ipv6_address(bytestring): address = ":".join(["%02s" % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper() address = bgp_shorten_ipv6_adress(address) return address def bgp_render_ip_address(bytestring): if len(bytestring) == 4: return bgp_render_ipv4_address(bytestring) elif len(bytestring) == 16: return bgp_render_ipv6_address(bytestring) else: return '' def cisco_bgp_get_peer(OID_END): # returns peer address string from OID_END # u'1.4.217.119.208.34.1.1' --> 217.119.208.34 # u'2.16.42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17.2.1' --> 42.5.87.192.0.0.255.255.0.0.0.0.0.0.0.17 peer_ip = '' OID_END = OID_END.split('.') if int(OID_END[1]) == 4: # length of ip address peer_ip = '.'.join(OID_END[2:6]) # ipv4 address elif int(OID_END[1]) == 16: # ipv6 address peer_ip = ':'.join('%02s' % hex(int(m))[2:] for m in OID_END[2:18]).replace(' ', '0').upper() peer_ip = bgp_shorten_ipv6_adress(peer_ip) return peer_ip def cisco_bgp_errors(bytestring): lasterrorhex = ''.join(["%02X " % ord(x) for x in bytestring]).strip() byte1, byte2 = lasterrorhex.split() names = {} names[0] = {0: 'NO ERROR'} names[1] = {0: 'Message', 2: 'Connection Not Synchronized', 3: 'Bad Message Length', 4: 'Bad Message Type', } names[2] = {0: 'OPEN', 1: 'Unsupported Version Number', 2: 'Bad Peer AS', 3: 'Bad BGP Identifier', 4: 'Unsupported Optional Parameter', 5: 'Authentication Failure', 6: 'Unacceptable Hold', } names[3] = {0: 'UPDATE', 1: 'Malformed Attribute List', 2: 'Unrecognized Well-known Attribute', 3: 'Missing Well-known Attribute', 4: 'Attribute Flags Error', 5: 'Attribute Length Error', 6: 'Invalid ORIGIN Attribute', 7: 'AS Routing Loop', 8: 'Invalid NEXT_HOP Attribute', 9: 'Optional Attribute Error', 10: 'Invalid Network Field', 11: 'Malformed AS_PATH', } names[4] = {0: 'Hold Timer Expired', } names[5] = {0: 'Finite State Machine Error', } names[6] = {0: 'Administratively Shutdown', 1: 'Max Prefix Reached', 2: 'Peer Unconfigured', 3: 'Administratively Reset', 4: 'Connection Rejected', 5: 'Other Configuration Change', } return names[int(byte1, 16)].get(int(byte2, 16)) # bgp not active if info == [[], []]: return None cbgpPeer2Entry, cbgpPeer2AddrFamily = info peer_prefixes = {} # create dictionary from cbgpPeer2AddrFamily ('remoteip addrfamilyname' as index) if len(cbgpPeer2AddrFamily) > 0 : for entry in cbgpPeer2AddrFamily: oid_end, addrfamilyname, acceptedprefixes, deniedprefixes, prefixadminlimit, prefixthreshold, \ prefixclearthreshold, advertisedprefixes, suppressedprefixes, withdrawnprefixes = entry if not oid_end == '': remoteaddr = cisco_bgp_get_peer(entry[0]) peer = { 'remoteaddr': remoteaddr, 'addrfamilyname': addrfamilyname } for key, value in [ ('prefixadminlimit', prefixadminlimit), ('prefixthreshold', prefixthreshold), ('prefixclearthreshold', prefixclearthreshold), ('acceptedprefixes', acceptedprefixes), ('advertisedprefixes', advertisedprefixes), ('deniedprefixes', deniedprefixes), ('suppressedprefixes', suppressedprefixes), ('withdrawnprefixes', withdrawnprefixes), ]: try: peer[key] = int(value) except ValueError: pass peer_prefixes.update({'%s %s' % (remoteaddr, addrfamilyname): peer}) # workaround: get remote ip from cbgpPeer2Entry if cbgpPeer2AddrFamilyName is missing :-( elif len(cbgpPeer2Entry) > 0: for entry in cbgpPeer2Entry: remoteaddr = cisco_bgp_get_peer(entry[0]) addrfamilyname = '' peer = {'remoteaddr': remoteaddr,} peer_prefixes.update({'%s %s' % (remoteaddr, addrfamilyname): peer}) # create dictionary from cbgpPeer2Entry (peer ip address as index) peer_table = {} for entry in cbgpPeer2Entry: oid_end, state, adminstatus, localaddr, localas, localidentifier, remoteas, remoteidentifier, inupdates, \ outupdates, intotalmessages, outtotalmessages, lasterror, fsmestablishedtransitions, fsmestablishedtime, \ inupdateelapsedtime, lasterrortxt, prevstate = entry if not oid_end == '': peer = {'remoteaddr': cisco_bgp_get_peer(oid_end), 'localaddr': bgp_render_ip_address(localaddr), 'localid': localidentifier, 'remoteid': remoteidentifier, 'lasterror': cisco_bgp_errors(lasterror), 'inupdateelapsedtime': inupdateelapsedtime, 'lasterrortxt': lasterrortxt, 'prevstate': int(prevstate), } for key, value in [ ('state', state), ('adminstate', adminstatus), ('localas', localas), ('remoteas', remoteas), ('inupdates', inupdates), ('outupdates', outupdates), ('intotalmessages', intotalmessages), ('outtotalmessages', outtotalmessages), ('fsmestablishedtransitions', fsmestablishedtransitions), ('fsmestablishedtime', fsmestablishedtime), ]: try: peer[key] = int(value) except ValueError: pass peer_table.update({'%s' % cisco_bgp_get_peer(oid_end): peer}) return [peer_prefixes, peer_table] ########################################################################### # # INVENTORY function # ########################################################################### def inventory_cisco_bgp_peer(parsed): if parsed: peer_prefixes, peer_table = parsed for key in peer_prefixes.keys(): yield key, {} ########################################################################### # # CHECK function # ########################################################################### def check_cisco_bgp_peer(item, params, parsed): def bgp_render_uptime(uptime): # expects time in seconds m, s = divmod(uptime, 60) # break in seconds / minutes h, m = divmod(m, 60) # break in mintes / hours if h >= 24: # more then one day d, h = divmod(h, 24) # break in hours / days else: return '%02d:%02d:%02d' % (h, m, s) if d >= 365: # more the one year y, d = divmod(d, 365) # break in days / years return '%dy %dd %02d:%02d:%02d' % (y, d, h, m, s) else: return '%dd %02d:%02d:%02d' % (d, h, m, s) def cisco_bgp_adminstate(state): names = {1: 'stop', 2: 'start', } return names.get(state, 'unknown (%s)' % state) def cisco_bgp_peerstate(state): names = {0: 'none', 1: 'idle', 2: 'connect', 3: 'active', 4: 'opensned', 5: 'openconfirm', 6: 'established'} return names.get(state, 'unknown (%s)' % state) peer_prefixes, peer_table = parsed prefixes = peer_prefixes.get(item, None) alias = '' peer_not_found_state = 3 for bgp_connection, bgp_alias, not_found_state in params.get('peer_list', []): if item == bgp_connection: alias = bgp_alias peer_not_found_state = not_found_state if prefixes: # state = 0 perfdata = [] infotext = '' longoutput = '' minuptime = 86400 if params.get('minuptime'): minuptime = params.get('minuptime') peer = peer_table.get(prefixes.get('remoteaddr')) if peer.get('localas') == 0: peer.update({'localas': params.get('useaslocalas')}) infotext_values = params.get('infotext_values', []) if alias != '': infotext += ', Alias: %s' % alias for key, value in [ ('remoteid', ', Remote ID: %s'), ('remoteas', ', Remote AS: %s'), ('localaddr', ', Local address: %s'), ('localid', ', Local ID: %s'), ('localas', ', Local AS: %s'), ]: try: if key not in infotext_values: infotext += value % peer[key] except KeyError: pass peerstate = peer.get('state') adminstate = peer.get('adminstate') establishedtime = peer.get('fsmestablishedtime') if peerstate == 1: # idle yield 2, 'Peer state: %s' % cisco_bgp_peerstate(peerstate) elif peerstate == 6: # established if establishedtime >= minuptime: infotext = 'Uptime: %s' % bgp_render_uptime(establishedtime) + infotext else: yield 1, 'Uptime: %s is less then min. uptime (%s)' % (bgp_render_uptime(establishedtime), bgp_render_uptime(minuptime)) else: # everything else yield 1, 'Peer state: %s' % cisco_bgp_peerstate(peerstate) if not adminstate == 2: # not start yield 1, 'Admin state: %s' % cisco_bgp_adminstate(adminstate) bgptype = '' if not peer.get('localas') == 0: if peer.get('remoteas') == peer.get('localas'): bgptype = ' (iBGP)' else: bgptype = ' (eBGP)' longoutput_data = [ ['IP-address (remote/local)', peer.get('remoteaddr'), peer.get('localaddr')], ['Router-ID (remote/local)', peer.get('remoteid'), peer.get('localid')], ['Autonomus System (remote/local)', peer.get('remoteas'), str(peer.get('localas')) + bgptype], ['State', cisco_bgp_peerstate(peerstate), ''], ['Admin state', cisco_bgp_adminstate(adminstate), ''], ['Last error', peer.get('lasterror'), ''], ['Last error text', peer.get('lasterrortxt'), ''], ['Previous state', cisco_bgp_peerstate(peer.get('prevstate')), ''], ['Address family name', prefixes.get('addrfamilyname', 'unknown'), ''], ['Prefix clear threshold (%)', '%.0d' % prefixes.get('prefixclearthreshold', 0), ''] , ] acceptedprefixes = prefixes.get('acceptedprefixes', None) prefixadminlimit = prefixes.get('prefixadminlimit', None) prefixthreshold = prefixes.get('prefixthreshold', None) if prefixadminlimit is not None and prefixthreshold is not None: warnthreshold = prefixadminlimit / 100.0 * prefixthreshold # use float (100.0) to get xx.xx in division longoutput_data.append(['Prefix admin limit (prefixes)', '%.0d' % prefixadminlimit, '']) longoutput_data.append(['Prefix threshold (prefixes/%)', '%.0d' % warnthreshold, '%.0d' % prefixthreshold]) else: warnthreshold = None if params.get('htmloutput', False): # # disable 'Escape HTML codes in plugin output' in wato --> global settings # table_bracket = '%s
' line_bracket = '%s' cell_bracket = '%s%s%s' cell_seperator = '' longoutput = '\n' + table_bracket % (''.join([line_bracket % cell_seperator.join([cell_bracket % (entry[0], entry[1], entry[2])]) for entry in longoutput_data])) else: longoutput += '\nfor nicer output' \ '\ndisable \'Escape HTML codes in plugin output\' in wato --> global settings and enable HTML output in \'Parameters for this service\'' for entry in longoutput_data: if not entry[2] == '': longoutput += '\n{}: {} / {}'.format(entry[0], entry[1], entry[2]) else: longoutput += '\n{}: {}'.format(entry[0], entry[1]) if prefixadminlimit is not None and acceptedprefixes is not None and warnthreshold is not None: if acceptedprefixes >= prefixadminlimit: yield 2, 'Prefix admin limit reached (%d/%d)' % (acceptedprefixes, prefixadminlimit) elif prefixthreshold > 0: perfdata.append(('acceptedprefixes', acceptedprefixes, warnthreshold, prefixadminlimit)) if acceptedprefixes >= warnthreshold: yield 1, 'Prefix warn threshold reached (%d/%d)' % (acceptedprefixes, warnthreshold) else: perfdata.append(('acceptedprefixes', acceptedprefixes, '', prefixadminlimit)) elif acceptedprefixes is not None: perfdata.append(('acceptedprefixes', acceptedprefixes)) now_time = time.time() rate_item = item.replace(' ', '_').replace(':','_') for key in [ 'deniedprefixes', 'advertisedprefixes', 'withdrawnprefixes', 'suppressedprefixes', 'inupdates', 'outupdates', 'intotalmessages', 'outtotalmessages', ]: try: value = get_rate('cisco_bgp_peer.%s.%s' % (key, rate_item), now_time, prefixes[key], onwrap=SKIP) perfdata.append((key, value)) except KeyError: pass for key in [ 'fsmestablishedtransitions', 'fsmestablishedtime', 'inupdateelapsedtime' ]: try: perfdata.append((key, peer[key])) except KeyError: pass if infotext[0:2] == ', ': infotext = infotext[2:] yield 0, infotext + longoutput, perfdata else: infotext = 'Item not found in SNMP data' if alias != '': infotext += ', Alias: %s' % alias yield peer_not_found_state, infotext ########################################################################### # # CHECK info # ########################################################################### check_info['cisco_bgp_peer'] = { 'check_function' : check_cisco_bgp_peer, 'inventory_function' : inventory_cisco_bgp_peer, 'service_description' : 'Cisco BGP peer %s', 'has_perfdata' : True, 'group' : 'cisco_bgp_peer', 'default_levels_variable' : 'cisco_bgp_peer_defaults', 'parse_function' : parse_cisco_bgp_peer, 'snmp_scan_function' : lambda oid: 'cisco'in oid('.1.3.6.1.2.1.1.1.0').lower(), 'snmp_info' : [ ('.1.3.6.1.4.1.9.9.187.1.2.5.1', # CISCO-BGP4-MIB::cbgpPeer2Entry [OID_END, '3', # cbgpPeer2State '4', # cbgpPeer2AdminStatus '6', # cbgpPeer2LocalAddr '8', # cbgpPeer2LocalAs -> empty '9', # cbgpPeer2LocalIdentifier '11', # cbgpPeer2RemoteAs '12', # cbgpPeer2RemoteIdentifier '13', # cbgpPeer2InUpdates '14', # cbgpPeer2OutUpdates '15', # cbgpPeer2InTotalMessages '16', # cbgpPeer2OutTotalMessages '17', # cbgpPeer2LastError '18', # cbgpPeer2FsmEstablishedTransitions '19', # cbgpPeer2FsmEstablishedTime '27', # cbgpPeer2InUpdateElapsedTime '28', # cbgpPeer2LastErrorTxt '29', # cbgpPeer2PrevState ]), ('.1.3.6.1.4.1.9.9.187.1.2', # cbgpPeer [OID_END, # # .7.1 --> cbgpPeer2AddrFamilyEntry '7.1.3', # cbgpPeer2AddrFamilyName # .8.1 --> cbgpPeer2AddrFamilyPrefixEntry '8.1.1', # cbgpPeer2AcceptedPrefixes '8.1.2', # cbgpPeer2DeniedPrefixes '8.1.3', # cbgpPeer2PrefixAdminLimit '8.1.4', # cbgpPeer2PrefixThreshold '8.1.5', # cbgpPeer2PrefixClearThreshold '8.1.6', # cbgpPeer2AdvertisedPrefixes '8.1.7', # cbgpPeer2SuppressedPrefixes '8.1.8', # cbgpPeer2WithdrawnPrefixes ]), ] }