diff --git a/README.md b/README.md index 484e5d15a31fab1e334ed18284f3889b03210eb6..9c1a93f3466bc7ef660d3f1ee1c4aaacca554e18 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.2.5-20240615.mkp "bgp_peer-2.2.5-20240615.mkp" +[PACKAGE]: ../../raw/master/mkp/bgp_peer-2.2.7-20241220.mkp "bgp_peer-2.2.7-20241220.mkp" # BGP Peer Check plugin to monitor the status of BGP peers and inventory plugin for static BGP peer data. diff --git a/mkp/bgp_peer-2.2.7-20241220.mkp b/mkp/bgp_peer-2.2.7-20241220.mkp new file mode 100644 index 0000000000000000000000000000000000000000..59ad0bae187747e0679c5abc9c59425e5d6ea64c Binary files /dev/null and b/mkp/bgp_peer-2.2.7-20241220.mkp differ diff --git a/source/agent_based/bgp_peer.py b/source/agent_based/bgp_peer.py index 0a3bfe19ad406c4419b5c1364e59504df1d59db9..df8172bb410fdfcae76032a51ff6e20a28d07f4a 100644 --- a/source/agent_based/bgp_peer.py +++ b/source/agent_based/bgp_peer.py @@ -35,6 +35,7 @@ # 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 @@ -53,7 +54,7 @@ # import time -from typing import Dict, Optional +from typing import Dict, List from cmk.base.plugins.agent_based.agent_based_api.v1 import ( register, @@ -83,24 +84,38 @@ from cmk.base.plugins.agent_based.utils.bgp_peer import ( ) -def parse_bgp_peer(string_table: StringTable) -> Optional[Dict[str, BgpPeer]]: +def parse_bgp_peer(string_table: List[StringTable]) -> Dict[str, BgpPeer] | None: peer_table = {} - for entry in string_table: - remote_addr, peer_state, admin_state, remote_as, in_updates, out_updates, in_messages, out_messages, \ - fsm_established_transitions, fsm_established_time, in_update_elapsed_time = entry + 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( - remote_addr=remote_addr, - peer_state=peer_state, admin_state=admin_state, - remote_as=remote_as, - in_updates=in_updates, - out_updates=out_updates, + 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, - fsm_established_transitions=fsm_established_transitions, - fsm_established_time=fsm_established_time, - in_update_elapsed_time=in_update_elapsed_time + 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) @@ -124,6 +139,19 @@ def discovery_bgp_peer(params, section: Dict[str, BgpPeer]) -> DiscoveryResult: 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( @@ -165,6 +193,7 @@ def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult: 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( @@ -180,6 +209,7 @@ def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult: ) 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 @@ -231,26 +261,37 @@ def check_bgp_peer(item, params, section: Dict[str, BgpPeer]) -> CheckResult: 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 - '2', # bgpPeerState - '3', # bgpPeerAdminStatus - '9', # bgpPeerRemoteAs - '10', # bgpPeerInUpdates - '11', # bgpPeerOutUpdates - '12', # bgpPeerInTotalMessages - '13', # bgpPeerOutTotalMessages - '15', # bgpPeerFsmEstablishedTransitions - '16', # bgpPeerFsmEstablishedTime - '24', # bgpPeerInUpdateElapsedTime - ] - ), + 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.*') ) diff --git a/source/agent_based/utils/bgp_peer.py b/source/agent_based/utils/bgp_peer.py index 616f18c3576085dec8c63eca394336b6576c481e..f8018022d7bbdd335fcd290b858834810287249b 100644 --- a/source/agent_based/utils/bgp_peer.py +++ b/source/agent_based/utils/bgp_peer.py @@ -26,7 +26,7 @@ import requests import json import ipaddress -from typing import List, Tuple, Optional, Dict, TypedDict +from typing import List, Tuple, Dict, TypedDict from dataclasses import dataclass @@ -39,22 +39,28 @@ class BgpPeerItem(TypedDict): @dataclass class BgpPeer: - peer_state: int # peer_statestr: str + accepted_prefixes: int | None + admin_state: int | None admin_statestr: str - metric_rate: List[Tuple[str, int]] - metric_count: List[Tuple[str, int]] + description: str | None + device_admin_limit: bool | None + fsm_established_time: int | None item: BgpPeerItem - admin_state: Optional[int] - fsm_established_time: Optional[int] - device_admin_limit: Optional[bool] - prefix_admin_limit: Optional[int] - prefix_threshold: Optional[int] - prefix_clear_threshold: Optional[int] - accepted_prefixes: Optional[int] - peer_unavail_reason: Optional[int] - peer_unavail_reason_str: Optional[str] - description: Optional[str] + local_addr: str | None + metric_count: List[Tuple[str, int]] + metric_rate: List[Tuple[str, int]] + peer_state: int + peer_unavail_reason: int | None + peer_unavail_reason_str: str | None + prefix_admin_limit: int | None + prefix_clear_threshold: int | None + prefix_threshold: int | None + remote_as: str | None + remote_addr: str | None + remote_id: str | None + local_as: str | None + local_id: str | None class InvBgpPeer(TypedDict): @@ -70,8 +76,8 @@ class InvBgpPeer(TypedDict): last_error_code: str last_error: str status_columns: Dict[str, str] - address_family: Optional[str] - fsm_established_time: Optional[int] + address_family: str | None + fsm_established_time: int | None def sec2hr(seconds): @@ -212,19 +218,24 @@ def bgp_get_ip_address_from_oid(oid_end): def bgp_get_peer_entry( + peer_state: str, remote_addr: str, remote_as: str, - peer_state: str, fsm_established_transitions: str, - fsm_established_time: Optional[str] = None, - admin_state: Optional[str] = None, - in_updates: Optional[str] = None, - out_updates: Optional[str] = None, - in_messages: Optional[str] = None, - out_messages: Optional[str] = None, - in_update_elapsed_time: Optional[str] = None, - description: Optional[str] = None, -) -> Optional[Dict[str, BgpPeer]]: + admin_state: str | None = None, + description: str | None = None, + fsm_established_time: str | None = None, + in_messages: str | None = None, + in_update_elapsed_time: str | None = None, + in_updates: str | None = None, + local_addr: str | None = None, + local_as: str | None = None, + local_id: str | None = None, + out_messages: str | None = None, + out_updates: str | None = None, + remote_id: str | None = None, + +) -> Dict[str, BgpPeer] | None: bgp_peer = BgpPeer( peer_state=int(peer_state), @@ -247,7 +258,13 @@ def bgp_get_peer_entry( accepted_prefixes=None, peer_unavail_reason=0, peer_unavail_reason_str='', - description=description if description else '' + description=description if description else '', + local_addr=local_addr, + remote_as=remote_as, + remote_addr=remote_addr, + remote_id=remote_id, + local_as=local_as, + local_id=local_id, ) for key, value in [ diff --git a/source/packages/bgp_peer b/source/packages/bgp_peer index e7ae3d6ac485a09b5906cc332a3911fd1bb0f1dd..9a52f1b874136d0b448f8b73dec41c442b2fd45f 100644 --- a/source/packages/bgp_peer +++ b/source/packages/bgp_peer @@ -37,7 +37,7 @@ 'web': ['plugins/views/inv_bgp_peer.py']}, 'name': 'bgp_peer', 'title': 'BGP Peer', - 'version': '2.2.5-20240615', + 'version': '2.2.7-20241220', 'version.min_required': '2.3.0b1', 'version.packaged': 'cmk-mkp-tool 0.2.0', 'version.usable_until': '2.4.0b1'}