diff --git a/bgp_peer-2.0.1-20230611.mkp b/bgp_peer-2.0.1-20230611.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..322502aab47095cb19f46e0dcd836ddf4b8f97a3
Binary files /dev/null and b/bgp_peer-2.0.1-20230611.mkp differ
diff --git a/bgp_peer-2.2.1-20230612.mkp b/bgp_peer-2.2.1-20230612.mkp
new file mode 100644
index 0000000000000000000000000000000000000000..516ed8629448dc176edecabe4598ca217129752a
Binary files /dev/null and b/bgp_peer-2.2.1-20230612.mkp differ
diff --git a/gui/wato/bgp_peer.py b/gui/wato/bgp_peer.py
new file mode 100644
index 0000000000000000000000000000000000000000..81489703db3d893e578d5d6cc06b47273a5f514c
--- /dev/null
+++ b/gui/wato/bgp_peer.py
@@ -0,0 +1,250 @@
+#!/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)
+
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    Integer,
+    TextAscii,
+    ListOf,
+    Tuple,
+    TextUnicode,
+    MonitoringState,
+    ListChoice,
+)
+
+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 no 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: TextAscii(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,
+    ))
diff --git a/gui/wato/inv_bgp_peer.py b/gui/wato/inv_bgp_peer.py
new file mode 100644
index 0000000000000000000000000000000000000000..f4832c661908036a3d309eb0b9f13b8dcba7db90
--- /dev/null
+++ b/gui/wato/inv_bgp_peer.py
@@ -0,0 +1,107 @@
+#!/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
+
+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,
+    ))