Collection of CheckMK checks (see https://checkmk.com/). All checks and plugins are provided as is. Absolutely no warranty. Send any comments to thl-cmk[at]outlook[dot]com

Skip to content
Snippets Groups Projects
Commit 255bc34a authored by thl-cmk's avatar thl-cmk :flag_na:
Browse files

modified for check APIv2, ruleset APIv1, graphing APIv1

parent cbf20fa5
No related branches found
No related tags found
No related merge requests found
Showing
with 1125 additions and 961 deletions
[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.2.8-20250117.mkp "bgp_peer-2.2.8-20250117.mkp"
[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.3.0-20250329.mkp "bgp_peer-2.3.0-20250329.mkp"
# BGP Peer
Check plugin to monitor the status of BGP peers and inventory plugin for static BGP peer data.
......
File added
#!/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 : 2021-08-20
# based on the BGP peer plugin by Thomas Wollner (tw@wollner-net.de)
#
# 2021-08-20: rewritten for CMK 2.0 by thl-cmk[at]outlook[dot]com
# 2021-08-21: added more perfdata, added metrics file
# 2021-08-22: added WATO options, streamlined with cisco_bgp_peer
# 2021-08-29: moved static (longoutput) to inventory plugin
# moved helper functions to utils/bgp_peer
# 2021-11-14: merged check function with cisco_bgp_peer
# moved parse function to utils/bgp_peer
# 2021-04-02: rewritten bgp neighbor state handling (made configurable)
# 2022-04-29: added upper/lower prefix limits from wato
# added info if device is admin prefix limit capable (device_admin_limit)
# 2022-05-09: made item name configurable (don't use address-family/routing-instance/VRF)
# 2022-05-11: changed bgp_get_peer_entry to get proper parameters instead of Nontransparent list
# added remote_as to BgpPeerItem
# 2022-09-05: added missing wato parameters to register.check_plugin check_default_parameters
# 2022-09-10: made more reliable on limited data (fsm_established_time and admin_state)
# (THX to martin[dot]pechstein[at]posteo[dot]de)
# 2022-09-11: optimized internal flow: > alias > not found > admin down > peer state > ...
# 2023-01-21: changed to always yield fsm_established_time (not only if beep connects, but also on all other states)
# 2023-01-22: fix output for admin_state
# 2023-02-16: changed for CMK 2.1 (moved gui files from local/share/.. to local/lib/..)
# fix type error in discovery (CMK2.1 GUI only)
# 2023-02-20: fix crash if metric data is None
# 2023-03-26: optimized output of metrics, GetRateError will not be set to 0 anymore
# 2023-08-17: fix removed internal_item form check_default_parameters (THX mail[at]bastian-kuhn[dot]de)
# added warning if internal_item is missing in params
# 2024-06-07: fixed crash on configured state mapping
# 2024-12-20: added local address/as/identifier for bgp_topology
# Example Agent Output:
# BGP4-MIB
# .1.3.6.1.2.1.15.3.1.1.192.168.254.2 = IpAddress: 192.168.254.2
# .1.3.6.1.2.1.15.3.1.2.192.168.254.2 = INTEGER: 3
# .1.3.6.1.2.1.15.3.1.3.192.168.254.2 = INTEGER: 2
# .1.3.6.1.2.1.15.3.1.4.192.168.254.2 = INTEGER: 4
# .1.3.6.1.2.1.15.3.1.5.192.168.254.2 = IpAddress: 0.0.0.0
# .1.3.6.1.2.1.15.3.1.7.192.168.254.2 = IpAddress: 192.168.254.2
# .1.3.6.1.2.1.15.3.1.9.192.168.254.2 = INTEGER: 65301
# .1.3.6.1.2.1.15.3.1.10.192.168.254.2 = Counter32: 0
# .1.3.6.1.2.1.15.3.1.11.192.168.254.2 = Counter32: 5
# .1.3.6.1.2.1.15.3.1.14.192.168.254.2 = Hex-STRING: 04 00
# .1.3.6.1.2.1.15.3.1.16.192.168.254.2 = Gauge32: 6586822
#
import time
from typing import Dict, List
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
register,
Service,
Result,
check_levels,
State,
SNMPTree,
exists,
get_rate,
GetRateError,
get_value_store,
# IgnoreResultsError,
Metric,
render,
)
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
DiscoveryResult,
CheckResult,
StringTable,
)
from cmk.base.plugins.agent_based.utils.bgp_peer import (
BgpPeer,
bgp_get_peer_entry,
bgp_adminstate,
bgp_peerstate,
)
def parse_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer] | None:
peer_table = {}
try:
peer_info, local_info = string_table
except ValueError:
return
try:
local_as, local_id = local_info[0]
except (IndexError, ValueError):
local_as, local_id = None, None
for entry in peer_info:
remote_addr, remote_id, peer_state, admin_state, local_addr, remote_as, in_updates, out_updates, \
in_messages, out_messages, fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry
bgp_peer = bgp_get_peer_entry(
admin_state=admin_state,
fsm_established_time=fsm_established_time,
fsm_established_transitions=fsm_established_transitions,
in_messages=in_messages,
in_update_elapsed_time=in_update_elapsed_time,
in_updates=in_updates,
local_addr=local_addr,
out_messages=out_messages,
out_updates=out_updates,
peer_state=peer_state,
remote_addr=remote_addr,
remote_as=remote_as,
remote_id=remote_id,
local_as=local_as,
local_id=local_id,
)
if bgp_peer:
peer_table.update(bgp_peer)
return peer_table
def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult:
_item_parts = [
'remote_address',
'remote_as',
'address_family',
'routing_instance',
]
for key in section.keys():
parameters = {'internal_item': key}
item = ''
for item_part in _item_parts:
if item_part not in params['build_item']:
item += f'{section[key].item[item_part]} '
item = item.strip(' ')
yield Service(item=item, parameters=parameters)
def bgp_peer_base_info(peer: BgpPeer) -> GeneratorExit:
for message, value in [
('Local AS:', peer.local_as),
('Local address:', peer.local_addr),
('Local identifier:', peer.local_id),
('Remote AS:', peer.remote_as),
('Remote address:', peer.remote_addr),
('Remote identifier:', peer.remote_id),
]:
if value is not None:
yield Result(state=State.OK, notice=f'{message} {value}')
def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult:
if not params.get('internal_item'):
yield Result(
state=State.WARN,
summary='This service is using old parameters (see details)',
details='This service is using old parameters. To refresh the parameters you need to do a "Tabula rasa" '
'(Discover services -> Remove all and find new)',
)
else:
item = params['internal_item']
neighborstate = {
'1': 2, # idle
'2': 1, # connect
'3': 1, # active
'4': 1, # opensent
'5': 1, # openconfirm
'6': 0, # established
}
neighborstate.update(params['neighborstate'])
peer_not_found_state = params['peernotfound']
for bgp_connection, bgp_alias, not_found_state in params.get('peer_list', []):
if item == bgp_connection:
if bgp_alias != '':
yield Result(state=State.OK, summary=f'[{bgp_alias}]', details=' ')
peer_not_found_state = not_found_state
# get item data
try:
peer = section[item]
except KeyError:
yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data')
return
if peer.description:
yield Result(state=State.OK, summary=f'[{peer.description}]', details=' ')
if peer.admin_state == 1: # shutdown
yield Result(state=State(params['admindown']), summary=f'Admin state: {bgp_adminstate(peer.admin_state)}')
yield from bgp_peer_base_info(peer)
return
yield Result(
state=State(neighborstate.get(str(peer.peer_state))),
notice=f'Peer state: {bgp_peerstate(peer.peer_state)}'
)
if peer.fsm_established_time: # always yield fsm_established time
yield Metric(
name=f'bgp_peer_fsmestablishedtime',
value=peer.fsm_established_time,
boundaries=(0, None)
)
if not peer.peer_state == 6: # not established
yield from bgp_peer_base_info(peer)
return
if peer.fsm_established_time: # if peer is established use fsm_established_time as uptime
yield from check_levels(
value=peer.fsm_established_time,
label='Uptime',
levels_lower=params['minuptime'],
render_func=render.timespan,
metric_name='bgp_peer_fsmestablishedtime',
)
if peer.peer_unavail_reason != 0: # huawei peer unavailable state
yield Result(state=State.CRIT, notice=F'Peer unavailable reason: {peer.peer_unavail_reason_str}')
if peer.device_admin_limit and peer.prefix_admin_limit is None:
yield Result(
state=State(params['noprefixlimit']),
notice='Prefix limit/warn threshold not configured on the device.',
)
acceptedprefixes = peer.accepted_prefixes
prefixadminlimit = peer.prefix_admin_limit
prefixthreshold = peer.prefix_threshold
warnthreshold = None
if prefixadminlimit is not None and prefixthreshold is not None:
warnthreshold = int(prefixadminlimit / 100.0 * prefixthreshold) # use float (100.0) to get xx.xx in division
if acceptedprefixes is not None and peer.peer_state == 6: # peer established and prefixes accepted
yield from check_levels(
value=acceptedprefixes,
metric_name='bgp_peer_acceptedprefixes',
levels_upper=params.get('accepted_prefixes_upper_levels', (warnthreshold, prefixadminlimit)),
levels_lower=params.get('accepted_prefixes_lower_levels'),
label='Prefixes accepted',
render_func=lambda v: f'{v}'
)
now_time = time.time()
value_store = get_value_store()
for key, value in peer.metric_rate:
try:
value = get_rate(value_store, f'{key}', now_time, value, raise_overflow=True)
except GetRateError:
continue
yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None))
for key, value in peer.metric_count:
if value is not None:
yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None))
yield from bgp_peer_base_info(peer)
register.snmp_section(
name='bgp_peer',
parse_function=parse_bgp_peer,
fetch=[
SNMPTree(
base='.1.3.6.1.2.1.15.3.1', # BGP4-MIB::BgpPeerEntry
oids=[
'7', # bgpPeerRemoteAddr
'1', # bgpPeerIdentifier
'2', # bgpPeerState
'3', # bgpPeerAdminStatus
'5', # bgpPeerLocalAddr
'9', # bgpPeerRemoteAs
'10', # bgpPeerInUpdates
'11', # bgpPeerOutUpdates
'12', # bgpPeerInTotalMessages
'13', # bgpPeerOutTotalMessages
'15', # bgpPeerFsmEstablishedTransitions
'16', # bgpPeerFsmEstablishedTime
'24', # bgpPeerInUpdateElapsedTime
]),
SNMPTree(
base='.1.3.6.1.2.1.15', # BGP4-MIB
oids=[
'2', # bgpLocalAs
'4', # bgpIdentifier (local)
])
],
detect=exists('.1.3.6.1.2.1.15.3.1.1.*')
)
register.check_plugin(
name='bgp_peer',
service_name='BGP peer %s',
discovery_function=discovery_bgp_peer,
discovery_default_parameters={
'build_item': [
# 'remote_address',
'remote_as',
# 'address_family',
# 'routing_instance',
]
},
discovery_ruleset_name='discovery_bgp_peer',
check_function=check_bgp_peer,
check_default_parameters={
'minuptime': (7200, 3600),
'peer_list': [],
'peernotfound': 2,
'admindown': 1,
'noprefixlimit': 1,
'neighborstate': {
'1': 2, # idle
'2': 1, # connect
'3': 1, # active
'4': 1, # opensent
'5': 1, # openconfirm
'6': 0, # established
},
},
check_ruleset_name='bgp_peer',
)
# dummy needed for CMK 2.30x to shadow the original file
\ No newline at end of file
#!/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 : 2021-08-20
# based on the BGP peer plugin by Thomas Wollner (tw@wollner-net.de)
#
# 2021-08-20: rewritten for CMK 2.0 by thl-cmk[at]outlook[dot]com
# 2021-08-21: added more perfdata, added metrics file
# 2021-08-22: added WATO options, streamlined with cisco_bgp_peer
# 2021-08-29: moved static (longoutput) to inventory plugin
# moved helper functions to utils/bgp_peer
# 2021-11-14: merged check function with cisco_bgp_peer
# moved parse function to utils/bgp_peer
# 2021-04-02: rewritten bgp neighbor state handling (made configurable)
# 2022-04-29: added upper/lower prefix limits from wato
# added info if device is admin prefix limit capable (device_admin_limit)
# 2022-05-09: made item name configurable (don't use address-family/routing-instance/VRF)
# 2022-05-11: changed bgp_get_peer_entry to get proper parameters instead of Nontransparent list
# added remote_as to BgpPeerItem
# 2022-09-05: added missing wato parameters to register.check_plugin check_default_parameters
# 2022-09-10: made more reliable on limited data (fsm_established_time and admin_state)
# (THX to martin[dot]pechstein[at]posteo[dot]de)
# 2022-09-11: optimized internal flow: > alias > not found > admin down > peer state > ...
# 2023-01-21: changed to always yield fsm_established_time (not only if beep connects, but also on all other states)
# 2023-01-22: fix output for admin_state
# 2023-02-16: changed for CMK 2.1 (moved gui files from local/share/.. to local/lib/..)
# fix type error in discovery (CMK2.1 GUI only)
# 2023-02-20: fix crash if metric data is None
# 2023-03-26: optimized output of metrics, GetRateError will not be set to 0 anymore
# 2023-08-17: fix removed internal_item form check_default_parameters (THX mail[at]bastian-kuhn[dot]de)
# added warning if internal_item is missing in params
# 2024-06-07: fixed crash on configured state mapping
# 2024-12-20: added local address/as/identifier for bgp_topology
# 2025-03-29: refactored for ruleset APIv1
# Example Agent Output:
# BGP4-MIB
# .1.3.6.1.2.1.15.3.1.1.192.168.254.2 = IpAddress: 192.168.254.2
# .1.3.6.1.2.1.15.3.1.2.192.168.254.2 = INTEGER: 3
# .1.3.6.1.2.1.15.3.1.3.192.168.254.2 = INTEGER: 2
# .1.3.6.1.2.1.15.3.1.4.192.168.254.2 = INTEGER: 4
# .1.3.6.1.2.1.15.3.1.5.192.168.254.2 = IpAddress: 0.0.0.0
# .1.3.6.1.2.1.15.3.1.7.192.168.254.2 = IpAddress: 192.168.254.2
# .1.3.6.1.2.1.15.3.1.9.192.168.254.2 = INTEGER: 65301
# .1.3.6.1.2.1.15.3.1.10.192.168.254.2 = Counter32: 0
# .1.3.6.1.2.1.15.3.1.11.192.168.254.2 = Counter32: 5
# .1.3.6.1.2.1.15.3.1.14.192.168.254.2 = Hex-STRING: 04 00
# .1.3.6.1.2.1.15.3.1.16.192.168.254.2 = Gauge32: 6586822
#
import time
from typing import Dict, List, Generator
from cmk.agent_based.v2 import (
CheckPlugin,
CheckResult,
DiscoveryResult,
GetRateError,
Metric,
Result,
SNMPSection,
SNMPTree,
Service,
State,
StringTable,
check_levels,
exists,
get_rate,
get_value_store,
render,
)
from cmk_addons.plugins.bgp_peer.lib.bgp_peer import (
BgpPeer,
bgp_adminstate,
bgp_get_peer_entry,
bgp_peerstate,
)
def parse_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer] | None:
peer_table = {}
try:
peer_info, local_info = string_table
except ValueError:
return None
try:
local_as, local_id = local_info[0]
except (IndexError, ValueError):
local_as, local_id = None, None
for entry in peer_info:
remote_addr, remote_id, peer_state, admin_state, local_addr, remote_as, in_updates, out_updates, \
in_messages, out_messages, fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry
bgp_peer = bgp_get_peer_entry(
admin_state=admin_state,
fsm_established_time=fsm_established_time,
fsm_established_transitions=fsm_established_transitions,
in_messages=in_messages,
in_update_elapsed_time=in_update_elapsed_time,
in_updates=in_updates,
local_addr=local_addr,
out_messages=out_messages,
out_updates=out_updates,
peer_state=peer_state,
remote_addr=remote_addr,
remote_as=remote_as,
remote_id=remote_id,
local_as=local_as,
local_id=local_id,
)
if bgp_peer:
peer_table.update(bgp_peer)
return peer_table
def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult:
_item_parts = [
'remote_address',
'remote_as',
'address_family',
'routing_instance',
]
for key in section.keys():
parameters = {'internal_item': key}
item = ''
for item_part in _item_parts:
if item_part not in params['build_item']:
item += f'{section[key].item[item_part]} '
item = item.strip(' ')
yield Service(item=item, parameters=parameters)
def bgp_peer_base_info(peer: BgpPeer) -> Generator:
for message, value in [
('Local AS:', peer.local_as),
('Local address:', peer.local_addr),
('Local identifier:', peer.local_id),
('Remote AS:', peer.remote_as),
('Remote address:', peer.remote_addr),
('Remote identifier:', peer.remote_id),
]:
if value is not None:
yield Result(state=State.OK, notice=f'{message} {value}')
def _rewrite_ruleset_needed(params: dict) -> bool:
for param, value in params.items():
match param:
case 'accepted_prefixes_lower_levels' | 'accepted_prefixes_upper_levels' | 'minuptime':
if isinstance(value, tuple) and len(value) == 2 \
and isinstance(value[0], int) and isinstance(value[1], int):
return True
case 'neighborstate':
for key in value.keys():
if key in '123456':
return True
case 'peer_list':
if isinstance(value[0], tuple):
return True
return False
def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult:
if not params.get('internal_item'):
yield Result(
state=State.WARN,
summary='This service is using old parameters (see details)',
details='This service is using old parameters. To refresh the parameters you need to do a "Tabula rasa" '
'(Discover services -> Remove all and find new)',
)
else:
item = params['internal_item']
if _rewrite_ruleset_needed(params):
yield Result(state=State.WARN,
summary='BGP ruleset needs to be opened and saved to migrate the ruleset to ruleset APIv1!')
return
neighbor_state = {
'1': 2, # idle
'2': 1, # connect
'3': 1, # active
'4': 1, # opensent
'5': 1, # openconfirm
'6': 0, # established
}
neighbor_state.update(params['neighborstate'])
peer_not_found_state = params['peernotfound']
for entry in params.get('peer_list', []):
if item == entry['bgp_peer']:
if entry.get('bgp_peer_alias'):
yield Result(state=State.OK, summary=f'[{entry["bgp_peer_alias"]}]', details=' ')
peer_not_found_state = entry.get('state_not_found', params['peernotfound'])
# get item data
try:
peer = section[item]
except KeyError:
yield Result(state=State(peer_not_found_state), summary='Item not found in SNMP data')
return
if peer.description:
yield Result(state=State.OK, summary=f'[{peer.description}]', details=' ')
if peer.admin_state == 1: # shutdown
yield Result(state=State(params['admindown']), summary=f'Admin state: {bgp_adminstate(peer.admin_state)}')
yield from bgp_peer_base_info(peer)
return
yield Result(
state=State(neighbor_state.get(str(peer.peer_state))),
notice=f'Peer state: {bgp_peerstate(peer.peer_state)}'
)
if peer.fsm_established_time: # always yield fsm_established time
yield Metric(
name=f'bgp_peer_fsmestablishedtime',
value=peer.fsm_established_time,
boundaries=(0, None)
)
if not peer.peer_state == 6: # not established
yield from bgp_peer_base_info(peer)
return
if peer.fsm_established_time: # if peer is established use fsm_established_time as uptime
yield from check_levels(
value=peer.fsm_established_time,
label='Uptime',
levels_upper=('no_levels', None),
levels_lower=params['minuptime'],
render_func=render.timespan,
metric_name='bgp_peer_fsmestablishedtime',
)
if peer.peer_unavail_reason != 0: # huawei peer unavailable state
yield Result(state=State.CRIT, notice=F'Peer unavailable reason: {peer.peer_unavail_reason_str}')
if peer.device_admin_limit and peer.prefix_admin_limit is None:
yield Result(
state=State(params['noprefixlimit']),
notice='Prefix limit/warn threshold not configured on the device.',
)
if peer.accepted_prefixes is not None and peer.peer_state == 6: # peer established and prefixes accepted
if peer.prefix_admin_limit is None or peer.prefix_threshold is None:
levels_upper = None
else:
# use float (100.0) to get xx.xx in division
levels_upper = (
'fixed', (int(peer.prefix_admin_limit / 100.0 * peer.prefix_threshold), peer.prefix_admin_limit)
)
yield from check_levels(
value=peer.accepted_prefixes,
metric_name='bgp_peer_acceptedprefixes',
levels_upper=params.get('accepted_prefixes_upper_levels', levels_upper),
levels_lower=params.get('accepted_prefixes_lower_levels'),
label='Prefixes accepted',
render_func=lambda v: f'{v}'
)
now_time = time.time()
value_store = get_value_store()
for key, value in peer.metric_rate:
try:
value = get_rate(value_store, f'{key}', now_time, value, raise_overflow=True)
except GetRateError:
continue
yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None))
for key, value in peer.metric_count:
if value is not None:
yield Metric(name=f'bgp_peer_{key}', value=value, boundaries=(0, None))
yield from bgp_peer_base_info(peer)
snmp_section_bgp_peer = SNMPSection(
name='bgp_peer',
parse_function=parse_bgp_peer,
fetch=[
SNMPTree(
base='.1.3.6.1.2.1.15.3.1', # BGP4-MIB::BgpPeerEntry
oids=[
'7', # bgpPeerRemoteAddr
'1', # bgpPeerIdentifier
'2', # bgpPeerState
'3', # bgpPeerAdminStatus
'5', # bgpPeerLocalAddr
'9', # bgpPeerRemoteAs
'10', # bgpPeerInUpdates
'11', # bgpPeerOutUpdates
'12', # bgpPeerInTotalMessages
'13', # bgpPeerOutTotalMessages
'15', # bgpPeerFsmEstablishedTransitions
'16', # bgpPeerFsmEstablishedTime
'24', # bgpPeerInUpdateElapsedTime
]),
SNMPTree(
base='.1.3.6.1.2.1.15', # BGP4-MIB
oids=[
'2', # bgpLocalAs
'4', # bgpIdentifier (local)
])
],
detect=exists('.1.3.6.1.2.1.15.3.1.1.*')
)
check_plugin_bgp_peer = CheckPlugin(
name='bgp_peer',
service_name='BGP peer %s',
discovery_function=discovery_bgp_peer,
discovery_default_parameters={
'build_item': [
# 'remote_address',
'remote_as',
# 'address_family',
# 'routing_instance',
]
},
discovery_ruleset_name='discovery_bgp_peer',
check_function=check_bgp_peer,
check_default_parameters={
'minuptime': ('fixed', (7200, 3600)),
'peer_list': [],
'peernotfound': 2,
'admindown': 1,
'noprefixlimit': 1,
'neighborstate': {
'idle': 2, # ........1
'connect': 1, # .....2
'active': 1, # ......3
'open_sent': 1, # ...4
'open_confirm': 1, # 5
'established': 0, # .6
},
},
check_ruleset_name='bgp_peer',
)
......@@ -18,18 +18,18 @@
import time
from typing import List
from cmk.base.plugins.agent_based.agent_based_api.v1 import (
from cmk.agent_based.v2 import (
InventoryPlugin,
InventoryResult,
OIDBytes,
SNMPSection,
SNMPTree,
StringByteTable,
TableRow,
exists,
register,
)
from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
InventoryResult,
StringByteTable,
)
from cmk.base.plugins.agent_based.utils.bgp_peer import (
from cmk_addons.plugins.bgp_peer.lib.bgp_peer import (
BgpWhois,
InvBgpPeer,
bgp_error_as_string,
......@@ -132,7 +132,7 @@ def inventory_bgp_peers(params, section) -> InventoryResult:
del whois
register.snmp_section(
snmp_section_inv_bgp_peer = SNMPSection(
name='inv_bgp_peer',
parse_function=parse_inv_bgp_peer,
fetch=[
......@@ -160,7 +160,7 @@ register.snmp_section(
detect=exists('.1.3.6.1.2.1.15.3.1.1.*')
)
register.inventory_plugin(
inventory_plugin_inv_bgp_peer = InventoryPlugin(
name='inv_bgp_peer',
inventory_function=inventory_bgp_peers,
inventory_default_parameters={
......
#!/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 : 2021-08-21
#
# BGP Peer metrics plugin
#
# 2024-05-17: fixed typo in range mac -> max (crashed graphs in cmk 2.3.)
# 2025-03-29: rewritten for graphing API v1
from cmk.graphing.v1 import Title, graphs, metrics, perfometers
UNIT_COUNTER = metrics.Unit(metrics.DecimalNotation(''), metrics.StrictPrecision(2))
UNIT_PER_SECOND = metrics.Unit(metrics.DecimalNotation('/s'))
UNIT_TIME = metrics.Unit(metrics.TimeNotation())
metric_bgp_peer_accepted_prefixes = metrics.Metric(
name='bgp_peer_acceptedprefixes',
title=Title("Prefixes accepted"),
unit=UNIT_COUNTER,
color=metrics.Color.DARK_PURPLE,
)
metric_bgp_peer_advertised_prefixes = metrics.Metric(
name='bgp_peer_advertisedprefixes',
title=Title("Prefixes advertised"),
unit=UNIT_PER_SECOND,
color=metrics.Color.CYAN,
)
metric_bgp_peer_denied_prefixes = metrics.Metric(
name='bgp_peer_deniedprefixes',
title=Title("Prefixes denied"),
unit=UNIT_PER_SECOND,
color=metrics.Color.YELLOW,
)
metric_bgp_peer_fsm_established_time = metrics.Metric(
name='bgp_peer_fsmestablishedtime',
title=Title("FSM last change"),
unit=UNIT_TIME,
color=metrics.Color.GREEN,
)
metric_bgp_peer_fsm_established_transitions = metrics.Metric(
name='bgp_peer_fsmestablishedtransitions',
title=Title("FSM transitions"),
unit=UNIT_COUNTER,
color=metrics.Color.YELLOW,
)
metric_bgp_peer_in_total_messages = metrics.Metric(
name='bgp_peer_intotalmessages',
title=Title("Messages received"),
unit=UNIT_PER_SECOND,
color=metrics.Color.DARK_BLUE,
)
metric_bgp_peer_in_update_elapsed_time = metrics.Metric(
name='bgp_peer_inupdateelapsedtime',
title=Title("Last update received"),
unit=UNIT_TIME,
color=metrics.Color.DARK_BLUE,
)
metric_bgp_peer_in_updates = metrics.Metric(
name='bgp_peer_inupdates',
title=Title("Updates received"),
unit=UNIT_PER_SECOND,
color=metrics.Color.YELLOW,
)
metric_bgp_peer_out_total_messages = metrics.Metric(
name='bgp_peer_outtotalmessages',
title=Title("Messages send"),
unit=UNIT_PER_SECOND,
color=metrics.Color.DARK_PINK,
)
metric_bgp_peer_out_updates = metrics.Metric(
name='bgp_peer_outupdates',
title=Title("Updates send"),
unit=UNIT_PER_SECOND,
color=metrics.Color.CYAN,
)
metric_bgp_peer_suppressed_prefixes = metrics.Metric(
name='bgp_peer_suppressedprefixes',
title=Title("Prefixes suppressed"),
unit=UNIT_PER_SECOND,
color=metrics.Color.DARK_PINK,
)
metric_bgp_peer_withdrawn_prefixes = metrics.Metric(
name='bgp_peer_withdrawnprefixes',
title=Title("Prefixes withdrawn"),
unit=UNIT_PER_SECOND,
color=metrics.Color.BLUE,
)
# Juniper specific metrics
metric_bgp_peer_in_prefixes = metrics.Metric(
name='bgp_peer_in_prefixes',
title=Title("Prefixes in"),
unit=UNIT_COUNTER,
color=metrics.Color.DARK_PURPLE,
)
metric_bgp_peer_in_prefixes_rejected = metrics.Metric(
name='bgp_peer_in_prefixes_rejected',
title=Title("Prefixes in rejected"),
unit=UNIT_COUNTER,
color=metrics.Color.YELLOW,
)
metric_bgp_peer_in_prefixes_active = metrics.Metric(
name='bgp_peer_in_prefixes_active',
title=Title("Prefixes in active"),
unit=UNIT_COUNTER,
color=metrics.Color.CYAN,
)
metric_bgp_peer_out_prefixes = metrics.Metric(
name='bgp_peer_out_prefixes',
title=Title("Prefixes out"),
unit=UNIT_COUNTER,
color=metrics.Color.BLUE,
)
# Huawei specific metrics
metric_bgp_peer_prefix_adv_counter = metrics.Metric(
name='bgp_peer_prefixadvcounter',
title=Title("Prefixes advertised"),
unit=UNIT_COUNTER,
color=metrics.Color.DARK_BLUE,
)
metric_bgp_peer_prefix_active_counter = metrics.Metric(
name='bgp_peer_prefixactivecounter',
title=Title("Prefixes active"),
unit=UNIT_COUNTER,
color=metrics.Color.CYAN,
)
metric_bgp_peer_prefix_rcv_counter = metrics.Metric(
name='bgp_peer_prefixrcvcounter',
title=Title("Prefixes received"),
unit=UNIT_COUNTER,
color=metrics.Color.DARK_PURPLE,
)
graph_bgp_peer_fms_transitions_last_change = graphs.Graph(
name='bgp_peer.fms_transitions_last_change',
title=Title("FSM established last change"),
minimal_range=graphs.MinimalRange(0, metrics.MaximumOf('bgp_peer_fsmestablishedtime', metrics.Color.GRAY, ), ),
compound_lines=['bgp_peer_fsmestablishedtime'],
)
graph_bgp_peer_prefixes_accepted = graphs.Graph(
name='bgp_peer.prefixes_accepted',
title=Title("Accepted Prefixes"),
minimal_range=graphs.MinimalRange(0, metrics.MaximumOf('bgp_peer_acceptedprefixes', metrics.Color.GRAY, ), ),
compound_lines=['bgp_peer_acceptedprefixes'],
simple_lines=[
metrics.CriticalOf('bgp_peer_acceptedprefixes'),
metrics.WarningOf('bgp_peer_acceptedprefixes'),
],
)
graph_bgp_peer_prefixes_per_second = graphs.Graph(
name='bgp_peer.prefixes_per_second',
title=Title("Prefixes/s"),
simple_lines=[
'bgp_peer_withdrawnprefixes',
'bgp_peer_suppressedprefixes',
'bgp_peer_deniedprefixes',
'bgp_peer_advertisedprefixes',
],
optional=[
'bgp_peer_withdrawnprefixes',
'bgp_peer_suppressedprefixes',
'bgp_peer_deniedprefixes',
'bgp_peer_advertisedprefixes',
],
)
graph_bgp_peer_updates_in_out = graphs.Bidirectional(
name='bgp_peer.updates_in_out',
title=Title("Updates"),
lower=graphs.Graph(
name='bgp_peer.updates_in_out_lower',
title=Title("Updates"),
compound_lines=['bgp_peer_outupdates'],
),
upper=graphs.Graph(
name='bgp_peer.updates_in_out_upper',
title=Title("Updates"),
compound_lines=['bgp_peer_inupdates'],
),
)
graph_bgp_peer_messages_in_out = graphs.Bidirectional(
name='bgp_peer.messages_in_out',
title=Title("Total messages"),
lower=graphs.Graph(
name='bgp_peer.messages_in_out_lower',
title=Title("Total messages"),
compound_lines=['bgp_peer_outtotalmessages'],
),
upper=graphs.Graph(
name='bgp_peer.messages_in_out_upper',
title=Title("Total messages"),
compound_lines=['bgp_peer_intotalmessages'],
),
)
graph_bgp_peer_fms_transitions_from_to = graphs.Graph(
name='bgp_peer.fms_transitions_from_to',
title=Title("FSM transitions from/to established"),
minimal_range=graphs.MinimalRange(
0, metrics.MaximumOf('bgp_peer_fsmestablishedtransitions', metrics.Color.GRAY, ),
),
compound_lines=['bgp_peer_fsmestablishedtransitions'],
)
graph_bgp_peer_time_since_last_update = graphs.Graph(
name='bgp_peer.time_since_last_update',
title=Title("Time since last update received"),
minimal_range=graphs.MinimalRange(
0, metrics.MaximumOf('bgp_peer_inupdateelapsedtime', metrics.Color.GRAY, ),
),
compound_lines=['bgp_peer_inupdateelapsedtime'],
)
# juniper prefixes
graph_bgp_peer_juniper_prefixes = graphs.Bidirectional(
name='bgp_peer.juniper_prefixes',
title=Title("Prefixes in/out"),
lower=graphs.Graph(
name='bgp_peer.juniper_prefixes_lower',
title=Title("Prefixes in/out"),
simple_lines=['bgp_peer_out_prefixes'],
),
upper=graphs.Graph(
name='bgp_peer.juniper_prefixes_upper',
title=Title("Prefixes in/out"),
simple_lines=[
'bgp_peer_in_prefixes_rejected',
'bgp_peer_in_prefixes_active',
'bgp_peer_in_prefixes',
],
),
)
# huawei prefixes
graph_huawei_bgp_peer_counter = graphs.Graph(
name='huawei_bgp_peer_counter',
title=Title("BGP prefix counter"),
simple_lines=[
'bgp_peer_prefixrcvcounter',
'bgp_peer_prefixactivecounter',
'bgp_peer_prefixadvcounter',
],
)
perfometer_bgp_peer_accepted_prefixes = perfometers.Stacked(
name='bgp_peer_stacked',
upper=perfometers.Perfometer(
name='bgp_peer_fsmestablishedtime',
segments=['bgp_peer_fsmestablishedtime'],
focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(2592000)) # ome month
),
lower=perfometers.Perfometer(
name='bgp_peer_acceptedprefixes',
segments=['bgp_peer_acceptedprefixes'],
focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(500000))
)
)
perfometer_bgp_peer_fsm_established_time = perfometers.Perfometer(
name='bgp_peer_fsmestablishedtime',
segments=['bgp_peer_fsmestablishedtime'],
focus_range=perfometers.FocusRange(perfometers.Closed(0), perfometers.Open(2592000)) # ome month
)
\ No newline at end of file
#!/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-25
#
# Check_MK bgp_peers WATO plugin
#
# 2021-03-27: rewrite for CMK 2.0
# 2021-08-21: modified for bgp_peer plugin (from cisco_bgp_peer)
# 2021-08-29: removed htmloutput and infotext_values option
# 2022-04-02: added bgp neighbour states
# 2022-04-29: added upper/lower prefix limit
# 2022-05-09: added discovery rule set
# 2022-05-11: added remote_as to build_item
# 2022-09-05: added internal_item to avoid warnings on cmk updates (THX to Jay2k1 for reporting the issue)
# 2023-06-11: moved wato file from ~local/lib/check_mk/gui/plugins/wato
# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters to override the build in wato plugin
# 2024-06-15: fixed typo (no not)
#
# Known issue: the override of the build in wato plugin will break the build in aritsa bgp peer plugin
from click import help_option
from cmk.rulesets.v1 import Help, Label, Title
from cmk.rulesets.v1.form_specs import (
DefaultValue,
DictElement,
Dictionary,
InputHint,
Integer,
LevelDirection,
LevelsType,
List,
MultipleChoice,
MultipleChoiceElement,
ServiceState,
SimpleLevels,
String,
TimeMagnitude,
TimeSpan,
migrate_to_integer_simple_levels,
)
from cmk.rulesets.v1.rule_specs import CheckParameters, DiscoveryParameters, Topic, HostAndItemCondition
from cmk.rulesets.v1.form_specs.validators import NumberInRange, Message, LengthInRange
item_parts = [
# MultipleChoiceElement(name='remote_address', title=Title('Peer remote address')),
MultipleChoiceElement(name='remote_as', title=Title('Remote AS')),
MultipleChoiceElement(name='address_family', title=Title('Address family')),
MultipleChoiceElement(name='routing_instance', title=Title('Routing instance/VRF')),
]
def _migrate_to_float(value: object) -> float:
if isinstance(value, int | float):
return float(value)
raise TypeError(value)
def _migrate_bgp_peer_list(value: object) -> list:
if not isinstance(value, list):
raise TypeError(value)
peer_list = []
for entry in value:
if isinstance(entry, tuple):
bgp_peer, bgp_peer_alias, state_not_found = entry
peer_list.append({
'bgp_peer': bgp_peer,
'bgp_peer_alias': bgp_peer_alias,
'state_not_found': state_not_found
})
else:
peer_list.append(entry)
return peer_list
def _migrate_neighbor_state(value: object) -> dict:
if not isinstance(value, dict):
raise TypeError(value)
state_map = {}
for state, value in value.items():
match state:
case '1':
state_map['idle'] = value
case '2':
state_map['connect'] = value
case '3':
state_map['active'] = value
case '4':
state_map['open_sent'] = value
case '5':
state_map['open_confirm'] = value
case '6':
state_map['established'] = value
case _:
state_map[state] = value
return state_map
def _parameter_form_check_bgp_peer():
return Dictionary(
elements={
'minuptime': DictElement(
parameter_form=SimpleLevels(
title=Title('Minimum uptime for peer'),
help_text=Help('Set the time in seconds, a peer must be up before the peer is considered sable.'),
prefill_levels_type=DefaultValue(LevelsType.FIXED),
prefill_fixed_levels=InputHint((7200, 3600)),
level_direction=LevelDirection.LOWER,
migrate=migrate_to_integer_simple_levels,
form_spec_template=TimeSpan(
displayed_magnitudes=[TimeMagnitude.SECOND, TimeMagnitude.MINUTE, TimeMagnitude.HOUR],
custom_validate=(NumberInRange(min_value=0),),
migrate=_migrate_to_float,
))),
'accepted_prefixes_upper_levels': DictElement(
parameter_form=SimpleLevels(
title=Title('Accepted prefixes upper levels'),
help_text=Help('The values from WATO are preferred to the values from the device.'),
prefill_levels_type=DefaultValue(LevelsType.FIXED),
prefill_fixed_levels=InputHint((0, 0)),
level_direction=LevelDirection.UPPER,
migrate=migrate_to_integer_simple_levels,
form_spec_template=Integer(
unit_symbol='prefixes',
custom_validate=(NumberInRange(min_value=0, ),)
))),
'accepted_prefixes_lower_levels': DictElement(
parameter_form=SimpleLevels(
title=Title('Accepted prefixes lower levels'),
help_text=Help('The values from WATO are preferred to the values from the device.'),
prefill_levels_type=DefaultValue(LevelsType.FIXED),
prefill_fixed_levels=InputHint((0, 0)),
level_direction=LevelDirection.LOWER,
migrate=migrate_to_integer_simple_levels,
form_spec_template=Integer(
unit_symbol='prefixes',
custom_validate=(NumberInRange(min_value=0, ),),
))),
'peernotfound': DictElement(
parameter_form=ServiceState(
title=Title('State if peer is not found.'),
help_text=Help('Default monitoring state if the peer is not found in the SNMP data'),
prefill=DefaultValue(2)
)),
'admindown': DictElement(
parameter_form=ServiceState(
prefill=DefaultValue(1),
title=Title('State if peer is admin shutdown.'),
help_text=Help('Monitoring state if the peer is admin shutdown')
)),
'neighborstate': DictElement(
parameter_form=Dictionary(
title=Title('State to report for BGP neighbor state'),
help_text=Help('Map each BGP state to a CheckMK monitoring state'),
migrate=_migrate_neighbor_state,
elements={
'idle': DictElement(
parameter_form=ServiceState(
title=Title('1 - idle'),
help_text=Help(
'This is the first stage of the BGP FSM. BGP detects a start event, tries to initiate a '
'TCP connection to the BGP peer, and also listens for a new connect from a peer router. '
'If an error causes BGP to go back to the Idle state for a second time, the '
'ConnectRetryTimer is set to 60 seconds and must decrement to zero before the connection '
'is initiated again. Further failures to leave the Idle state result in the '
'ConnectRetryTimer doubling in length from the previous time. '
'Default monitoring state is "CRIT"'
),
prefill=DefaultValue(2)
)),
'connect': DictElement(
parameter_form=ServiceState(
title=Title('2 - connect'),
help_text=Help(
'In this state, BGP initiates the TCP connection. If the 3-way TCP handshake completes, '
'the established BGP Session BGP process resets the ConnectRetryTimer and sends the Open '
'message to the neighbor, and then changes to the OpenSent State.'
'Default monitoring state is "WARN"'),
prefill=DefaultValue(1),
)),
'active': DictElement(
parameter_form=ServiceState(
title=Title('3 - active'),
help_text=Help(
'In this state, BGP starts a new 3-way TCP handshake. If a connection is established, '
'an Open message is sent, the Hold Timer is set to 4 minutes, and the state moves to '
'OpenSent. If this attempt for TCP connection fails, the state moves back to the Connect '
'state and resets the ConnectRetryTimer. '
'Default monitoring state is "WARN"'),
prefill=DefaultValue(1),
)),
'open_sent': DictElement(
parameter_form=ServiceState(
title=Title('4 - opensent'),
help_text=Help(
'In this state, an Open message has been sent from the originating router and is awaiting '
'an Open message from the other router. After the originating router receives the OPEN '
'message from the other router, both OPEN messages are checked for errors. If the Open '
'messages do not have any errors, the Hold Time is negotiated (using the lower value), '
'and a KEEPALIVE message is sent (assuming the value is not set to zero). The connection '
'state is then moved to OpenConfirm. If an error is found in the OPEN message, a '
'Notification message is sent, and the state is moved back to Idle.'
' Default monitoring state is "WARN"'),
prefill=DefaultValue(1),
)),
'open_confirm': DictElement(
parameter_form=ServiceState(
title=Title('5 - openconfirm'),
help_text=Help(
'In this state, BGP waits for a Keepalive or Notification message. Upon receipt of a '
'neighbor’s Keepalive, the state is moved to Established. If the hold timer expires, a '
'stop event occurs, or a Notification message is received, and the state is moved to '
'Idle. '
'Default monitoring state is "WARN"'),
prefill=DefaultValue(1),
)),
'established': DictElement(
parameter_form=ServiceState(
title=Title('6 - established'),
help_text=Help(
'In this state, the BGP session is established. BGP neighbors exchange routes via Update '
'messages. As Update and Keepalive messages are received, the Hold Timer is reset. If the '
'Hold Timer expires, an error is detected and BGP moves the neighbor back to the Idle '
'state. '
'Default monitoring state is "OK"'),
prefill=DefaultValue(0),
)),
}
)),
'noprefixlimit': DictElement(
parameter_form=ServiceState(
title=Title('State if no admin prefix limit/warn threshold is configured.'),
help_text=Help(
'The admin prefix limit and warn threshold needs to be configured on the device. '
'For example: "neighbor 172.17.10.10 maximum-prefix 10000 80". The threshold is in percentage '
'of the prefix limit.'
),
prefill=DefaultValue(1),
)),
'peer_list': DictElement(
parameter_form=List(
title=Title('BGP Peers'),
add_element_label=Label('Add BGP peer'),
remove_element_label=Label('remove BGP peer'),
no_element_label=Label('Add at least one BGP peer'),
migrate=_migrate_bgp_peer_list,
element_template=Dictionary(
elements={
'bgp_peer': DictElement(
required=True,
parameter_form=String(
title=Title('BGP peer'),
help_text=Help(
'The configured value must match a BGP item reported by the monitored '
'device. For example: "10.194.115.98" or "2A10:1CD0:1020:135::20 IPv6 Unicast"'
),
custom_validate=(LengthInRange(min_value=1, ),),
)),
'bgp_peer_alias': DictElement(
parameter_form=String(
title=Title('BGP Peer Alias'),
help_text=Help(
'You can configure an individual alias here for the BGP peer matching '
'the text configured in the "BGP Peer IP-address" field. The alias will '
'be shown in the check info'
),
custom_validate=(LengthInRange(min_value=1, ),),
)),
'state_not_found': DictElement(
required=True,
parameter_form=ServiceState(
title=Title('State if not found'),
help_text=Help(
'You can configure an individual state if the BGP peer matching the text '
'configured in the "BGP Peer IP-address" field is not found'
),
prefill=DefaultValue(2),
)),
}
)
)),
'internal_item': DictElement(
render_only=True,
parameter_form=MultipleChoice(
title=Title('Information not to use in the item name'),
elements=item_parts,
)),
}
)
rule_spec_check_bgp_peer = CheckParameters(
name='bgp_peer',
parameter_form=_parameter_form_check_bgp_peer,
title=Title('BGP Peer'),
topic=Topic.NETWORKING,
condition=HostAndItemCondition(item_title=Title('BGP peer')),
)
def _parameter_form_discovery_bgp_peer():
return Dictionary(
elements={
'build_item': DictElement(
parameter_form=MultipleChoice(
title=Title('Information not to use in the item name'),
help_text=Help(
'The Peer remote address is always used as the item name. By default the check will add the '
'address-family and the routing instance/VRF if available. You can decide to not use these '
'additional information in the item name. Do so only if your peers have only one address-'
'family configured and you don\'t have the same peer remote address in different routing '
'instances/VRFs configured.'
),
elements=item_parts,
prefill=DefaultValue(['remote_as'])
)
)
}
)
rule_spec_discovery_bgp_beer = DiscoveryParameters(
title=Title('BGP peer'),
topic=Topic.NETWORKING,
name='discovery_bgp_peer',
parameter_form=_parameter_form_discovery_bgp_peer,
)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Author: thl-cmk[at]outlook[dot]com
# URL : https://thl-cmk.hopto.org
# Date : 2022-04-24
#
# 2022-04-24: added option for BGP down time
# added option to remove some columns from inventory
# 2022-04-28: added Whois options
# 2023-06-12: moved wato file from ~local/lib/check_mk/gui/plugins/wato
# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters
# 2025-03-29: rewritten for rulesets API v1
from cmk.rulesets.v1 import Title, Help
from cmk.rulesets.v1.form_specs import (
DefaultValue,
DictElement,
Dictionary,
Integer,
MultipleChoice,
MultipleChoiceElement,
SingleChoice,
SingleChoiceElement,
TimeMagnitude,
TimeSpan,
)
from cmk.rulesets.v1.rule_specs import InventoryParameters, Topic
from cmk.rulesets.v1.form_specs.validators import NumberInRange, Message
def _migrate_to_float(value: object) -> float:
if isinstance(value, int | float):
return float(value)
raise TypeError(value)
def _parameter_form_inv_bgp_peer():
remove_columns = [
# MultipleChoiceElement(name='remote_as', title=Title('Remote AS')),
# MultipleChoiceElement(name='remote_id', title=Title('Remote ID')),
# MultipleChoiceElement(name='local_addr', title=Title('Local address')),
# MultipleChoiceElement(name='local_as', title=Title('Local AS')),
# MultipleChoiceElement(name='local_id', title=Title('Local ID')),
# MultipleChoiceElement(name='prev_state', title=Title('Previous state')),
MultipleChoiceElement(name='address_family', title=Title('Address family')),
MultipleChoiceElement(name='last_error', title=Title('Last error')),
MultipleChoiceElement(name='last_error_code', title=Title('Last error code')),
MultipleChoiceElement(name='as_name', title=Title('Remote AS name')),
MultipleChoiceElement(name='as_org_name', title=Title('Remote AS Org Name')),
MultipleChoiceElement(name='bgp_type', title=Title('Type')),
MultipleChoiceElement(name='version', title=Title('Version')),
]
rir_s = [
SingleChoiceElement(name='afrinic', title=Title('AFRINIC (https://rdap.afrinic.net/rdap)')),
SingleChoiceElement(name='apnic', title=Title('APNIC (https://rdap.apnic.net)')),
SingleChoiceElement(name='arin', title=Title('ARIN (https://rdap.arin.net/registry)')),
SingleChoiceElement(name='ripe', title=Title('RIPE (https://rdap.db.ripe.net)')),
SingleChoiceElement(name='lacnic', title=Title('LACNIC (https://rdap.apnic.net)')),
]
return Dictionary(
elements={
'not_in_service_time': DictElement(
parameter_form=TimeSpan(
title=Title('Time peer is not up until considered not in service'),
displayed_magnitudes=[TimeMagnitude.MINUTE, TimeMagnitude.HOUR, TimeMagnitude.DAY],
prefill=DefaultValue(2592000.0), # 30 days in seconds
migrate=_migrate_to_float,
)),
'remove_columns': DictElement(
parameter_form=MultipleChoice(
title=Title('List of columns to remove'),
help_text=Help('Information to remove from inventory'),
elements=remove_columns,
)),
'whois_enable': DictElement(
parameter_form=Dictionary(
title=Title('Add whois data to the inventory'),
help_text=Help(
'The whois data will be fetched via RDAP from the registries. For this the the plugin tries to'
'find the best registry via the RDAP bootstrap data from https://data.iana.org/rdap/asn.json.'
'The query it self will go to the found registry via http(s). Note: the request might be get '
'redirected if there a different authoritative registry for the ASn'
),
elements={
'whois_rir': DictElement(
parameter_form=SingleChoice(
title=Title('Preferred RIR to fetch whois data'),
help_text=Help(
'This registry will be used if the plugin can not determine the authoritative registry '
'based on the bootstrap data.'
),
elements=rir_s,
prefill=DefaultValue('ripe'),
)),
'whois_timeout': DictElement(
parameter_form=Integer(
custom_validate=(
NumberInRange(
min_value=1,
max_value=None,
error_msg=Message('The timeout must be greater than 0')
),
),
help_text=Help('The connection timeout for each whois request.'),
prefill=DefaultValue(5),
title=Title('Timeout for connections to RIRs'),
unit_symbol='seconds',
)),
}
)
)
}
)
rule_spec_inv_bgp_peer = InventoryParameters(
name='inv_bgp_peer',
parameter_form=_parameter_form_inv_bgp_peer,
title=Title('BGP peer'),
topic=Topic.NETWORKING,
)
#!/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 : 2021-08-21
#
# BGP Peer metrics plugin
#
# 2024-05-17: fixed typo in range mac -> max (crashed graphs in cmk 2.3.)
#
from cmk.gui.i18n import _
from cmk.gui.plugins.metrics.utils import (
metric_info,
graph_info,
perfometer_info
)
#####################################################################################################################
#
# define metrics for bgp peer perfdata
#
#####################################################################################################################
metric_info['bgp_peer_inupdates'] = {
'title': _('Updates received'),
'unit': '1/s',
'color': '22/a',
}
metric_info['bgp_peer_outupdates'] = {
'title': _('Updates send'),
'unit': '1/s',
'color': '32/a',
}
metric_info['bgp_peer_intotalmessages'] = {
'title': _('Messages received'),
'unit': '1/s',
'color': '42/a',
}
metric_info['bgp_peer_outtotalmessages'] = {
'title': _('Messages send'),
'unit': '1/s',
'color': '13/a',
}
metric_info['bgp_peer_fsmestablishedtransitions'] = {
'title': _('FSM transitions'),
'unit': 'count',
'color': '23/a',
}
metric_info['bgp_peer_fsmestablishedtime'] = {
'title': _('FSM last change'),
'unit': 's',
'color': '26/a',
}
metric_info['bgp_peer_inupdateelapsedtime'] = {
'title': _('Last update received'),
'unit': 's',
'color': '43/a',
}
metric_info['bgp_peer_acceptedprefixes'] = {
'title': _('Prefixes accepted'),
'help': _('number of accepted prefixes'),
'unit': 'count',
'color': '11/a',
}
metric_info['bgp_peer_deniedprefixes'] = {
'title': _('Prefixes denied'),
'unit': '1/s',
'color': '21/a',
}
metric_info['bgp_peer_advertisedprefixes'] = {
'title': _('Prefixes advertised'),
'unit': '1/s',
'color': '31/a',
}
metric_info['bgp_peer_withdrawnprefixes'] = {
'title': _('Prefixes withdrawn'),
'unit': '1/s',
'color': '41/a',
}
metric_info['bgp_peer_suppressedprefixes'] = {
'title': _('Prefixes suppressed'),
'unit': '1/s',
'color': '12/a',
}
# Juniper specific metrics
metric_info['bgp_peer_in_prefixes'] = {
'title': _('Prefixes in'),
'unit': 'count',
'color': '11/a',
}
metric_info['bgp_peer_in_prefixes_rejected'] = {
'title': _('Prefixes in rejected'),
'unit': 'count',
'color': '21/a',
}
metric_info['bgp_peer_in_prefixes_active'] = {
'title': _('Prefixes in active'),
'unit': 'count',
'color': '31/a',
}
metric_info['bgp_peer_out_prefixes'] = {
'title': _('Prefixes out'),
'unit': 'count',
'color': '41/a',
}
# Hawei spezific metrics
metric_info['bgp_peer_prefixrcvcounter'] = {
'title': _('Prefixes received'),
'unit': 'count',
'color': '11/a',
}
metric_info['bgp_peer_prefixactivecounter'] = {
'title': _('Prefixes active'),
'unit': 'count',
'color': '33/a',
}
metric_info['bgp_peer_prefixadvcounter'] = {
'title': _('Prefixes advertised'),
'unit': 'count',
'color': '43/a',
}
######################################################################################################################
#
# how to graph perdata for bgp peer
#
######################################################################################################################
graph_info['bgp_peer.fms_transitions_last_change'] = {
'title': _('FSM established last change'),
'metrics': [
('bgp_peer_fsmestablishedtime', 'area'),
],
'range': (0, 'bgp_peer_fsmestablishedtime:max'),
}
graph_info['bgp_peer.prefixes_accepted'] = {
'title': _('Accepted Prefixes'),
'metrics': [
('bgp_peer_acceptedprefixes', 'area'),
],
'scalars': [
('bgp_peer_acceptedprefixes:crit', _('crit')),
('bgp_peer_acceptedprefixes:warn', _('warn')),
],
'range': (0, 'bgp_peer_acceptedprefixes:max'),
}
graph_info['bgp_peer.prefixes_per_second'] = {
'title': _('Prefixes/s'),
'metrics': [
('bgp_peer_withdrawnprefixes', 'line'),
('bgp_peer_suppressedprefixes', 'line'),
('bgp_peer_deniedprefixes', 'line'),
('bgp_peer_advertisedprefixes', 'line'),
],
'optional_metrics': [
'bgp_peer_withdrawnprefixes',
'bgp_peer_suppressedprefixes',
'bgp_peer_deniedprefixes',
'bgp_peer_advertisedprefixes',
],
}
graph_info['bgp_peer.updates_in_out'] = {
'title': _('Updates'),
'metrics': [
('bgp_peer_outupdates', '-area'),
('bgp_peer_inupdates', 'area'),
]
}
graph_info['bgp_peer.messages_in_out'] = {
'title': _('Total messages'),
'metrics': [
('bgp_peer_outtotalmessages', '-area'),
('bgp_peer_intotalmessages', 'area'),
]
}
graph_info['bgp_peer.fms_transitions_from_to'] = {
'title': _('FSM transitions from/to established'),
'metrics': [
('bgp_peer_fsmestablishedtransitions', 'area'),
],
'range': (0, 'bgp_peer_fsmestablishedtransitions:max'),
}
graph_info['bgp_peer.time_since_last_update'] = {
'title': _('Time since last update received'),
'metrics': [
('bgp_peer_inupdateelapsedtime', 'area'),
],
'range': (0, 'bgp_peer_inupdateelapsedtime:max'),
}
# juniper prefixes
graph_info['bgp_peer.juniper_prefixes'] = {
'title': _('Prefixes in/out'),
'metrics': [
('bgp_peer_out_prefixes', '-line'),
('bgp_peer_in_prefixes_rejected', 'line'),
('bgp_peer_in_prefixes_active', 'line'),
('bgp_peer_in_prefixes', 'line'),
],
}
# huawei prefixes
graph_info['huawei_bgp_peer_counter'] = {
'title': _('BGP prefix counter'),
'metrics': [
('bgp_peer_prefixrcvcounter', 'line'),
('bgp_peer_prefixactivecounter', 'line'),
('bgp_peer_prefixadvcounter', 'line'),
]
}
######################################################################################################################
#
# define perf-o-meter for bgp peer uptime + prefixes accepted/advertised
#
######################################################################################################################
perfometer_info.append(('stacked', [
{
'type': 'logarithmic',
'metric': 'bgp_peer_fsmestablishedtime',
'half_value': 2592000.0, # ome month
'exponent': 2,
},
{
'type': 'logarithmic',
'metric': 'bgp_peer_acceptedprefixes',
'half_value': 500000.0,
'exponent': 2,
}
]))
perfometer_info.append({
'type': 'logarithmic',
'metric': 'bgp_peer_fsmestablishedtime',
'half_value': 2592000.0, # ome month
'exponent': 2,
})
#!/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-25
#
# Check_MK bgp_peers WATO plugin
#
# 2021-03-27: rewrite for CMK 2.0
# 2021-08-21: modified for bgp_peer plugin (from cisco_bgp_peer)
# 2021-08-29: removed htmloutput and infotext_values option
# 2022-04-02: added bgp neighbour states
# 2022-04-29: added upper/lower prefix limit
# 2022-05-09: added discovery rule set
# 2022-05-11: added remote_as to build_item
# 2022-09-05: added internal_item to avoid warnings on cmk updates (THX to Jay2k1 for reporting the issue)
# 2023-06-11: moved wato file from ~local/lib/check_mk/gui/plugins/wato
# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters to override the build in wato plugin
# 2024-06-15: fixed typo (no not)
#
# Known issue: the override of the build in wato plugin will break the build in aritsa bgp peer plugin
from cmk.gui.i18n import _
from cmk.gui.valuespec import (
Dictionary,
Integer,
TextAscii,
ListOf,
Tuple,
TextUnicode,
MonitoringState,
ListChoice,
TextInput,
)
from cmk.gui.plugins.wato.utils import (
CheckParameterRulespecWithItem,
rulespec_registry,
RulespecGroupCheckParametersNetworking,
HostRulespec,
RulespecGroupCheckParametersDiscovery,
)
def _parameter_valuespec_bgp_peer():
return Dictionary(
elements=[
('minuptime',
Tuple(
title=_('Minimum uptime for peer'),
orientation='horizontal',
help=_('Set the time in seconds, a peer must be up before the peer is considered sable.'),
elements=[
Integer(title=_('Warning below'), unit='seconds', default_value=7200, minvalue=0),
Integer(title=_('Critical below'), unit='seconds', default_value=3600, minvalue=0)
],
)),
('accepted_prefixes_upper_levels',
Tuple(
title=_('Accepted prefixes upper levels'),
help=_('The values from WATO are preferred to the values from the device.'),
orientation='horizontal',
elements=[
Integer(title=_('Warning at'), minvalue=0, unit=_('prefixes'), size=5),
Integer(title=_('Critical at'), minvalue=0, unit=_('prefixes'), size=5),
],
)),
('accepted_prefixes_lower_levels',
Tuple(
title=_('Accepted prefixes lower levels'),
orientation='horizontal',
elements=[
Integer(title=_('Warning below'), minvalue=0, unit=_('prefixes'), size=5),
Integer(title=_('Critical below'), minvalue=0, unit=_('prefixes'), size=5),
],
)),
('peernotfound',
MonitoringState(
default_value=2,
title=_('State if peer is not found.'),
help=_('Default monitoring state if the peer is not found in the SNMP data')
)),
('admindown',
MonitoringState(
default_value=1,
title=_('State if peer is admin shutdown.'),
help=_('Monitoring state if the peer is admin shutdown')
)),
('neighborstate',
Dictionary(
title=_('State to report for BGP neighbor state'),
help=_('Map each BGP state to a CheckMK monitoring state'),
elements=[
('1',
MonitoringState(
title=_('1 - idle'),
help=_(
'This is the first stage of the BGP FSM. BGP detects a start event, tries to initiate a '
'TCP connection to the BGP peer, and also listens for a new connect from a peer router. '
'If an error causes BGP to go back to the Idle state for a second time, the '
'ConnectRetryTimer is set to 60 seconds and must decrement to zero before the connection '
'is initiated again. Further failures to leave the Idle state result in the '
'ConnectRetryTimer doubling in length from the previous time. '
'Default monitoring state is "CRIT"'),
default_value=2,
)),
('2',
MonitoringState(
title=_('2 - connect'),
help=_(
'In this state, BGP initiates the TCP connection. If the 3-way TCP handshake completes, '
'the established BGP Session BGP process resets the ConnectRetryTimer and sends the Open '
'message to the neighbor, and then changes to the OpenSent State.'
'Default monitoring state is "WARN"'),
default_value=1,
)),
('3',
MonitoringState(
title=_('3 - active'),
help=_('In this state, BGP starts a new 3-way TCP handshake. If a connection is established, '
'an Open message is sent, the Hold Timer is set to 4 minutes, and the state moves to '
'OpenSent. If this attempt for TCP connection fails, the state moves back to the Connect '
'state and resets the ConnectRetryTimer. '
'Default monitoring state is "WARN"'),
default_value=1,
)),
('4',
MonitoringState(
title=_('4 - opensent'),
help=_(
'In this state, an Open message has been sent from the originating router and is awaiting '
'an Open message from the other router. After the originating router receives the OPEN '
'message from the other router, both OPEN messages are checked for errors. If the Open '
'messages do not have any errors, the Hold Time is negotiated (using the lower value), '
'and a KEEPALIVE message is sent (assuming the value is not set to zero). The connection '
'state is then moved to OpenConfirm. If an error is found in the OPEN message, a '
'Notification message is sent, and the state is moved back to Idle.'
' Default monitoring state is "WARN"'),
default_value=1,
)),
('5',
MonitoringState(
title=_('5 - openconfirm'),
help=_('In this state, BGP waits for a Keepalive or Notification message. Upon receipt of a '
'neighbor’s Keepalive, the state is moved to Established. If the hold timer expires, a '
'stop event occurs, or a Notification message is received, and the state is moved to '
'Idle. '
'Default monitoring state is "WARN"'),
default_value=1,
)),
('6',
MonitoringState(
title=_('6 - established'),
help=_(
'In this state, the BGP session is established. BGP neighbors exchange routes via Update '
'messages. As Update and Keepalive messages are received, the Hold Timer is reset. If the '
'Hold Timer expires, an error is detected and BGP moves the neighbor back to the Idle '
'state. '
'Default monitoring state is "OK"'),
default_value=0,
)),
])),
('noprefixlimit',
MonitoringState(
default_value=1,
title=_('State if no admin prefix limit/warn threshold is configured.'),
help=_('The admin prefix limit and warn threshold needs to be configured on the device. '
'For example: "neighbor 172.17.10.10 maximum-prefix 10000 80". The threshold is in percentage '
'of the prefix limit.')
)),
('peer_list',
ListOf(
Tuple(
orientation='horizontal',
elements=[
TextUnicode(
title=_('BGP Peer'),
help=_('The configured value must match a BGP item reported by the monitored '
'device. For example: "10.194.115.98" or "2A10:1CD0:1020:135::20 IPv6 Unicast"'),
allow_empty=False,
size=50,
),
TextUnicode(
title=_('BGP Peer Alias'),
help=_('You can configure an individual alias here for the BGP peer matching '
'the text configured in the "BGP Peer IP-address" field. The alias will '
'be shown in the check info'),
size=50,
),
MonitoringState(
default_value=2,
title=_('State if not found'),
help=_('You can configure an individual state if the BGP peer matching the text '
'configured in the "BGP Peer IP-address" field is not found')
),
]),
add_label=_('Add BGP peer'),
movable=False,
title=_('BGP Peers'),
)),
('internal_item', # added by plugin discovery function
TextUnicode()),
],
hidden_keys=['internal_item'],
)
rulespec_registry.register(
CheckParameterRulespecWithItem(
check_group_name='bgp_peer',
group=RulespecGroupCheckParametersNetworking,
item_spec=lambda: TextInput(title=_('BGP peer'), ),
match_type='dict',
parameter_valuespec=_parameter_valuespec_bgp_peer,
title=lambda: _('BGP peer'),
))
def _valuespec_discovery_bgp_peer():
item_parts = [
# ('remote_address', 'Peer remote address'),
('remote_as', 'Remote AS'),
('address_family', 'Address family'),
('routing_instance', 'Routing instance/VRF'),
]
return Dictionary(
title=_('BGP peer'),
elements=[
('build_item',
ListChoice(
title=_('Information not to use in the item name'),
help=_(
'The Peer remote address is always used as the item name. By default the check will add the '
'address-family and the routing instance/VRF if available. You can decide to not use these '
'additional information in the item name. Do so only if your peers have only one address-'
'family configured and you don\'t have the same peer remote address in different routing '
'instances/VRFs configured.'
),
choices=item_parts,
default_value=['remote_as'],
)),
],
)
rulespec_registry.register(
HostRulespec(
group=RulespecGroupCheckParametersDiscovery,
match_type='dict',
name='discovery_bgp_peer',
valuespec=_valuespec_discovery_bgp_peer,
))
# dummy to shadow build in bgp peer rule set
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Author: thl-cmk[at]outlook[dot]com
# URL : https://thl-cmk.hopto.org
# Date : 2022-04-24
#
# 2022-04-24: added option for BGP down time
# added option to remove some columns from inventory
# 2022-04-28: added Whois options
# 2023-06-12: moved wato file from ~local/lib/check_mk/gui/plugins/wato
# to ~/local/lib/check_mk/gui/plugins/wato/check_parameters
from cmk.gui.i18n import _
from cmk.gui.plugins.wato.utils import (
HostRulespec,
rulespec_registry,
)
from cmk.gui.valuespec import (
Dictionary,
ListChoice,
Age,
DropdownChoice,
Integer,
)
from cmk.gui.plugins.wato.inventory import (
RulespecGroupInventory,
)
def _valuespec_inv_bgp_peer():
removecolumns = [
# ('remote_as', 'Remote AS'),
# ('remote_id', 'Remote ID'),
# ('local_addr', 'Local address'),
# ('local_as', 'Local AS'),
# ('local_id', 'Local ID'),
('address_family', 'Address family'),
('last_error', 'Last error'),
('last_error_code', 'Last error code'),
# ('prev_state', 'Previous state'),
('as_name', 'Remote AS name'),
('as_org_name', 'Remote AS Org Name'),
('bgp_type', 'Type'),
('version', 'Version'),
]
return Dictionary(
title=_('BGP peer'),
elements=[
('not_in_service_time',
Age(
title=_('Time peer is not up until considered not in service'),
default_value=2592000, # 30 days in seconds,
)),
('remove_columns',
ListChoice(
title=_('List of columns to remove'),
help=_('Information to remove from inventory'),
choices=removecolumns,
default_value=[],
)),
('whois_enable',
Dictionary(
title=_('Add whois data to the inventory'),
help=_(
'The whois data will be fetched via RDAP from the registries. For this the the plugin tries to'
'find the best registry via the RDAP bootstrap data from https://data.iana.org/rdap/asn.json.'
'The query it self will go to the found registry via http(s). Note: the request might be get '
'redirected if there a different authoritative registry for the ASn'
),
elements=[
('whois_rir',
DropdownChoice(
title='Preferred RIR to fetch whois data',
help=_(
'This registry will be used if the plugin can not determine the authoritative registry '
'based on the bootstrap data.'
),
choices=[
('afrinic', _('AFRINIC (https://rdap.afrinic.net/rdap)')),
('apnic', _('APNIC (https://rdap.apnic.net)')),
('arin', _('ARIN (https://rdap.arin.net/registry)')),
('ripe', _('RIPE (https://rdap.db.ripe.net)')),
('lacnic', _('LACNIC (https://rdap.apnic.net)')),
]
)),
('whois_timeout',
Integer(
title='Timeout for connections to RIRs',
help=_('The connection timeout for each whois request.'),
default_value=5,
minvalue=1,
unit=_('seconds'),
)),
]
)),
],
)
rulespec_registry.register(
HostRulespec(
group=RulespecGroupInventory,
match_type='dict',
name='inv_parameters:inv_bgp_peer',
valuespec=_valuespec_inv_bgp_peer,
))
......@@ -27,17 +27,19 @@
'https://thl-cmk.hopto.org/gitlab/checkmk/juniper-networks/juniper_bgp_peer\n'
'\n',
'download_url': 'https://thl-cmk.hopto.org/vendor-independent/bgp_peer',
'files': {'agent_based': ['bgp_peer.py',
'inv_bgp_peer.py',
'utils/bgp_peer.py'],
'checkman': ['bgp_peer'],
'gui': ['metrics/bgp_peer.py',
'wato/check_parameters/bgp_peer.py',
'wato/check_parameters/inv_bgp_peer.py'],
'files': {'agent_based': ['bgp_peer.py'],
'cmk_addons_plugins': ['bgp_peer/agent_based/bgp_peer.py',
'bgp_peer/agent_based/inv_bgp_peer.py',
'bgp_peer/graphing/bgp_peer.py',
'bgp_peer/lib/bgp_peer.py',
'bgp_peer/rulesets/bgp_peer.py',
'bgp_peer/rulesets/inv_bgp_peer.py',
'bgp_peer/checkman/bgp_peer'],
'gui': ['wato/check_parameters/bgp_peer.py'],
'web': ['plugins/views/inv_bgp_peer.py']},
'name': 'bgp_peer',
'title': 'BGP Peer',
'version': '2.2.8-20250117',
'version': '2.3.0-20250329',
'version.min_required': '2.3.0b1',
'version.packaged': 'cmk-mkp-tool 0.2.0',
'version.usable_until': '2.4.0b1'}
'version.usable_until': '2.5.0b1'}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment