checkmk-plugins/check_mk-cisco_bgp_peer/local/lib/check_mk/base/plugins/agent_based/cisco_bgp_peer.py

666 lines
29 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# License: GNU General Public License v2
#
# Author: thl-cmk[at]outlook[dot]com
# URL : https://thl-cmk.hopto.org
# Date : 2017-12-26
#
# Monitor status of Cisco BGP Peer (IPv4 and IPv6)
#
# 2018-05-24: changed counters to 1/s
# 2018-05-25: 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)
# 2018-05-27: changed scan function from '.1.3.6.1.4.1.9.9.187.1.2.7.1.3.* to sysdecr contains cisco
# 2018-05-28: changed wato, added peer alias, state if not found, infotext values
# 2018-05-29: fixed longoutpout (removed not configured)
# 2018-11-02: modified scanfunction (from "find 'cisco' =-1" to "'cisco' in OID"
# 2019-18-02: added fix for empty values ("" instead of "0") sugested by Laurent Barbier (lbarbier[at]arkane-studios[dot]com)
# 2020-02-24: added workaround for missing cbgpPeer2AddrFamily (example L2VPN EVPN peers, Fix for jonale82[at]gmail[dot]com)
# 2020-03-02: changed handling of perfdata, add only data the are really there (not None, instead of setting them to 0)
# 2020-06-04: code cleanup --> changed isdigit test to try/except loop, changed peer.get test to try/except loop
# 2020-09-10: fixed typo in metrics file. FMS --> FSM (thanks martin[dot]pechstein[at]posteo[dot]de)
# 2021-03-27: rewrite for CMK2.0
# 2021-03-28: added warning for missing admin prefix limit/warn threshold
# 2023-01-15: modified by Spearhead Systems to support CISCO-BGP4-MIB::CbgpPeer3Entry
#
# snmpwalk sample
#
# CISCO-BGP4-MIB::cbgpPeer2AddrFamilyEntry
#
# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c <removed> 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 <removed> 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 <removed> 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 <removed> 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 <removed> 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']
# ]
# ]
#
#
#
from dataclasses import dataclass
import re, time
from typing import Mapping, Dict, List, Tuple, NamedTuple
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
DiscoveryResult,
CheckResult,
StringTable,
)
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
register,
Service,
Result,
check_levels,
State,
SNMPTree,
contains,
OIDEnd,
get_rate,
get_value_store,
Metric,
render,
)
@dataclass
class Section:
peer_prefixes: dict
peer_table: dict
###########################################################################
#
# DATA Parser function
#
###########################################################################
def parse_cisco_bgp_peer(string_table: List[StringTable]) -> Section:
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(len(OID_END)) == 7: # length of ip address
peer_ip = '.'.join(OID_END[3:7]) # 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 not string_table == [[], [], []]:
cbgpPeer2Entry, cbgpPeer3Entry, cbgpPeer2AddrFamily = string_table
cbgpPeerEntry = cbgpPeer2Entry + cbgpPeer3Entry
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
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 cbgpPeerEntry if cbgpPeer2AddrFamilyName is missing :-(
elif len(cbgpPeerEntry) > 0:
for entry in cbgpPeerEntry:
remoteaddr = cisco_bgp_get_peer(entry[0])
addrfamilyname = ''
peer = {'remoteaddr': remoteaddr, }
peer_prefixes.update({'%s %s' % (remoteaddr, addrfamilyname): peer})
# create dictionary from cbgpPeerEntry (peer ip address as index)
peer_table = {}
for entry in cbgpPeerEntry:
oid_end, state, adminstatus, localaddr, localas, localidentifier, remoteas, remoteidentifier, inupdates, \
outupdates, intotalmessages, outtotalmessages, lasterror, fsmestablishedtransitions, fsmestablishedtime, \
inupdateelapsedtime, lasterrortxt, prevstate = entry
peer = {'remoteaddr': cisco_bgp_get_peer(oid_end),
'localaddr': bgp_render_ip_address(localaddr),
'localid': localidentifier,
'remoteid': remoteidentifier,
'lasterror': cisco_bgp_errors(lasterror),
'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),
('inupdateelapsedtime', inupdateelapsedtime),
]:
try:
peer[key] = int(value)
except ValueError:
pass
peer_table.update({'%s' % cisco_bgp_get_peer(oid_end): peer})
return Section(
peer_prefixes=peer_prefixes,
peer_table=peer_table,
)
###########################################################################
#
# INVENTORY function
#
###########################################################################
def discovery_cisco_bgp_peer(section: Section) -> DiscoveryResult:
for key in section.peer_prefixes.keys():
yield Service(item=key)
###########################################################################
#
# CHECK function
#
###########################################################################
def check_cisco_bgp_peer(item, params, section) -> CheckResult:
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 = section.peer_prefixes
peer_table = section.peer_table
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:
longoutput = ''
peer = peer_table.get(prefixes.get('remoteaddr'))
if peer.get('localas') == 0:
peer.update({'localas': params.get('useaslocalas')})
if alias != '':
yield Result(state=State.OK, summary='Alias: %s' % alias)
peerstate = peer.get('state')
adminstate = peer.get('adminstate')
establishedtime = peer.get('fsmestablishedtime')
if peerstate == 1: # idle
yield Result(state=State.CRIT, summary='Peer state: %s' % cisco_bgp_peerstate(peerstate))
elif peerstate == 6: # established
yield from check_levels(
value=establishedtime,
label='Uptime',
levels_lower=params['minuptime'],
render_func=render.timespan
)
else: # everything else
yield Result(state=State.WARN, summary='Peer state: %s' % cisco_bgp_peerstate(peerstate))
if not adminstate == 2: # not start
yield Result(state=State.WARN, summary='Admin state: %s' % cisco_bgp_adminstate(adminstate))
for key, value in [
('remoteid', 'Remote ID: %s'),
('remoteas', 'Remote AS: %s'),
('localaddr', 'Local address: %s'),
('localid', 'Local ID: %s'),
('localas', 'Local AS: %s'),
]:
if key in params['infotext_values']:
try:
yield Result(state=State.OK, summary=value % peer[key])
except KeyError:
pass
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:
yield Result(state=State(params['noprefixlimit']), notice='No admin prefix limit/warn threshold configured on the device.')
warnthreshold = None
if params.get('htmloutput', False):
#
# disable 'Escape HTML codes in plugin output' in wato --> global settings
#
table_bracket = '<table border="1">%s</table>'
line_bracket = '<tr>%s</tr>'
cell_bracket = '<td>%s</td><td>%s</td><td>%s</td>'
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:
yield from check_levels(
value=acceptedprefixes,
metric_name='cisco_bgp_peer_acceptedprefixes',
levels_upper=(warnthreshold, prefixadminlimit),
label='Prefixes accepted',
render_func=lambda v: '%s' % str(v)
)
now_time = time.time()
value_store = get_value_store()
rate_item = item.replace(' ', '_').replace(':', '_')
for key in [
'deniedprefixes',
'advertisedprefixes',
'withdrawnprefixes',
'suppressedprefixes',
'inupdates',
'outupdates',
'intotalmessages',
'outtotalmessages',
]:
try:
value = get_rate(value_store, 'cisco_bgp_peer.%s.%s' % (key, rate_item), now_time, prefixes[key],
raise_overflow=False)
yield Metric(name='cisco_bgp_peer_%s' % key, value=value, boundaries=(0, None))
except KeyError:
pass
for key in [
'fsmestablishedtransitions',
'fsmestablishedtime',
'inupdateelapsedtime'
]:
try:
yield Metric(name='cisco_bgp_peer_%s' % key, value=peer[key], boundaries=(0, None))
except KeyError:
pass
yield Result(state=State.OK, notice=longoutput)
else:
if alias != '':
yield Result(state=State.OK, summary=', Alias: %s' % alias)
yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data')
###########################################################################
#
# CHECK info
#
###########################################################################
register.snmp_section(
name='cisco_bgp_peer',
parse_function=parse_cisco_bgp_peer,
fetch=[
SNMPTree(
base='.1.3.6.1.4.1.9.9.187.1.2.5.1', # CCISCO-BGP4-MIB::cbgpPeer2Entry
oids=[
OIDEnd(),
'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
]
),
SNMPTree(
base='.1.3.6.1.4.1.9.9.187.1.2.9.1', # CCISCO-BGP4-MIB::cbgpPeer3Entry
oids=[
OIDEnd(),
'5', # cbgpPeer3State
'6', # cbgpPeer3AdminStatus
'8', # cbgpPeer3LocalAddr
'10', # cbgpPeer3LocalAs -> empty
'11', # cbgpPeer3LocalIdentifier
'13', # cbgpPeer3RemoteAs
'14', # cbgpPeer3RemoteIdentifier
'15', # cbgpPeer3InUpdates
'16', # cbgpPeer3OutUpdates
'17', # cbgpPeer3InTotalMessages
'18', # cbgpPeer3OutTotalMessages
'19', # cbgpPeer3LastError
'20', # cbgpPeer3FsmEstablishedTransitions
'21', # cbgpPeer3FsmEstablishedTime
'29', # cbgpPeer3InUpdateElapsedTime
'30', # cbgpPeer3LastErrorTxt
'31', # cbgpPeer3PrevState
]
),
SNMPTree(
base='.1.3.6.1.4.1.9.9.187.1.2', # cbgpPeer
oids=[
OIDEnd(), #
# .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
]
)
],
detect=contains('.1.3.6.1.2.1.1.1.0', 'Cisco'),
)
register.check_plugin(
name='cisco_bgp_peer',
service_name='Cisco BGP peer %s',
discovery_function=discovery_cisco_bgp_peer,
check_function=check_cisco_bgp_peer,
check_default_parameters={
'minuptime': (7200, 3600),
'useaslocalas': 0,
'htmloutput': False,
'noprefixlimit': 1,
'infotext_values': [],
'peer_list': [],
},
check_ruleset_name='cisco_bgp_peer',
)