From dce662beffb1b1ac3c6e57350c49fe7ac68f74b5 Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Sat, 2 Oct 2021 12:27:11 +0200
Subject: [PATCH] update project

---
 agent_based/ospfv3_general.py     |  15 +-
 agent_based/ospfv3_interface.py   |  20 +-
 agent_based/ospfv3_neighbor.py    |  42 ++--
 agent_based/ospfv3_virtuallink.py |  42 ++--
 ospfv3.mkp                        | Bin 9626 -> 13187 bytes
 packages/ospfv3                   |   8 +-
 web/plugins/metrics/ospfv3.py     |   2 +-
 web/plugins/wato/ospfv3.py        | 370 ++++++++++++++++++++++++++++++
 8 files changed, 453 insertions(+), 46 deletions(-)
 create mode 100644 web/plugins/wato/ospfv3.py

diff --git a/agent_based/ospfv3_general.py b/agent_based/ospfv3_general.py
index c6f909e..ff62f86 100644
--- a/agent_based/ospfv3_general.py
+++ b/agent_based/ospfv3_general.py
@@ -10,6 +10,7 @@
 # Monitor status of OSPFv3 general status
 #
 # 2021-09-17: rewritten for CMK 2.0
+# 2021-10-02: added WATO options
 #
 # sample snmpwalk
 # .1.3.6.1.2.1.191.1.1.1.0 = Gauge32: 50529054
@@ -111,8 +112,11 @@ def parse_ospfv3_general(string_table: StringTable) -> Optional[OspfV3General]:
     )
 
 
-def discovery_ospfv3_general(section: OspfV3General) -> DiscoveryResult:
-    yield Service()
+def discovery_ospfv3_general(params, section: OspfV3General) -> DiscoveryResult:
+    if section.AdminStatus != 'disabled':
+        yield Service()
+    elif params['admin_disabled']:
+        yield Service()
 
 
 def check_ospfv3_general(params, section: OspfV3General) -> CheckResult:
@@ -128,7 +132,7 @@ def check_ospfv3_general(params, section: OspfV3General) -> CheckResult:
     yield Result(state=State.OK, notice=f'Stub router advertisement: {section.StubRouterAdvertisement}')
 
     if section.AdminStatus == 'disabled':
-        yield Result(state=State.WARN, notice='Admin disabled')
+        yield Result(state=State(params['state_admin_disabled']), notice='Admin disabled')
 
     yield Metric(name='ospf3_general_lsacount', value=section.AsScopeLsaCount)
     yield Metric(name='ospf3_general_rxnewlsas', value=section.RxNewLsas)
@@ -178,6 +182,11 @@ register.check_plugin(
     discovery_function=discovery_ospfv3_general,
     check_function=check_ospfv3_general,
     check_default_parameters={
+        'state_admin_disabled': 1,
     },
     check_ruleset_name='ospfv3_general',
+    discovery_ruleset_name='discovery_ospfv3_general',
+    discovery_default_parameters={
+        'admin_disabled': False,
+    },
 )
diff --git a/agent_based/ospfv3_interface.py b/agent_based/ospfv3_interface.py
index 9e01868..479e318 100644
--- a/agent_based/ospfv3_interface.py
+++ b/agent_based/ospfv3_interface.py
@@ -10,6 +10,7 @@
 # Monitor status of OSPFv3 enabled interfaces
 #
 # 2021-09-17: rewritten for CMK 2.0
+# 2021-10-02: added WATO options
 #
 # sample snmpwalk
 #
@@ -186,7 +187,13 @@ def check_ospfv3_interface(item, params, section: Dict[str, OspfV3Interface]) ->
     yield Result(state=State.OK, summary=f'Area: {interface.IfAreaId}')
     yield Result(state=State.OK, summary=f'DR: {interface.IfDesignatedRouter}')
     yield Result(state=State.OK, summary=f'BDR: {interface.IfBackupDesignatedRouter}')
-    yield Result(state=State.OK, summary=f'State: {interface.IfState}')
+
+    if interface.IfState in ['down']:
+        yield Result(state=State(params['state_if_down']), notice=f'State: {interface.IfState}')
+    elif interface.IfState in ['waiting', 'standby']:
+        yield Result(state=State(params['state_if_wait_stby']), notice=f'State: {interface.IfState}')
+    else:
+        yield Result(state=State.OK, summary=f'State: {interface.IfState}')
 
     yield Result(state=State.OK, notice=f'Link scope LSA checksum: {interface.IfLinkLsaCksumSum}')
     yield Result(state=State.OK, notice=f'Interface type: {interface.IfType}')
@@ -197,13 +204,7 @@ def check_ospfv3_interface(item, params, section: Dict[str, OspfV3Interface]) ->
     yield Result(state=State.OK, notice=f'Interface metric value: {interface.IfMetricValue}')
 
     if interface.IfAdminStatus == 'disabled':
-        yield Result(state=State.WARN, notice='Admin status is disabled')
-
-    if interface.IfState in ['down']:
-        yield Result(state=State.CRIT, notice=f'State is {interface.IfState}')
-
-    if interface.IfState in ['waiting', 'standby']:
-        yield Result(state=State.WARN, notice=f'state is {interface.IfState}')
+        yield Result(state=State(params['state_admin_disabled']), notice='Admin status is disabled')
 
     yield Metric(name='ospfv3_interface_events', value=interface.IfEvents)
     yield Metric(name='ospfv3_interface_linkscopelsacount', value=interface.IfLinkScopeLsaCount)
@@ -259,6 +260,9 @@ register.check_plugin(
     discovery_function=discovery_ospfv3_interface,
     check_function=check_ospfv3_interface,
     check_default_parameters={
+        'state_admin_disabled': 1,
+        'state_if_down': 2,
+        'state_if_wait_stby': 1,
     },
     check_ruleset_name='ospfv3_interface',
 )
diff --git a/agent_based/ospfv3_neighbor.py b/agent_based/ospfv3_neighbor.py
index f074333..f349bad 100644
--- a/agent_based/ospfv3_neighbor.py
+++ b/agent_based/ospfv3_neighbor.py
@@ -10,6 +10,7 @@
 # Monitor status of OSPFv3 neighbors
 #
 # 2021-09-17: rewritten for CMK 2.0
+# 2021-10-02: added WATO options
 #
 # .1.3.6.1.2.1.191.1.9.1.4.1.0.50529054 = INTEGER: 2
 # .1.3.6.1.2.1.191.1.9.1.5.1.0.50529054 = Hex-STRING: FE 80 00 00 00 00 00 00 01 92 01 68 00 00 00 03
@@ -160,27 +161,41 @@ def discovery_ospfv3_neighbor(section: Dict[str, OspfV3Neighbor]) -> DiscoveryRe
 
 
 def check_ospfv3_neighbor(item, params, section: Dict[str, OspfV3Neighbor]) -> CheckResult:
+
+    not_found_state = params['state_not_found']
+
+    for neighbour, neighbourAlias, neighbourNotFoundState in params.get('peer_list', []):
+        if item == neighbour:
+            yield Result(state=State.OK, summary=f'[{neighbourAlias}]')
+            not_found_state = neighbourNotFoundState
+
     try:
         neighbor = section[item]
     except KeyError:
-        yield Result(state=State.UNKNOWN, notice='Item not found in SNMP data')
+        yield Result(state=State(not_found_state), notice='Item not found in SNMP data')
         return
 
-    nbrstatus = ospf_nbr_state(neighbor.nbrState)
+    # default monitoring states for ospfNbrState
+    neighbor_states = {
+        '1': 2,  # down
+        '2': 1,  # attempt
+        '3': 1,  # init
+        '4': 0,  # twoWay
+        '5': 1,  # exchangeStart
+        '6': 1,  # exchange
+        '7': 1,  # loading
+        '8': 0,  # full
+    }
 
     yield Result(state=State.OK, summary=f'Neighbor ID: {neighbor.nbrRtrId}')
-    # yield Result(state=State.OK, summary=f'. on interface: {neighbor.nbrLocalInterface}')
+    # yield Result(state=State.OK, summary=f'On interface: {neighbor.nbrLocalInterface}')
 
-    nbrstate = neighbor.nbrState
+    neighbor_states.update(params.get('neighbor_states', neighbor_states))  # update neighbor_states with params
 
-    if nbrstate in params['critical_states']:
-        yield Result(state=State.CRIT, notice=f'State: {nbrstatus}')
-    elif nbrstate in params['warning_states']:
-        yield Result(state=State.WARN, notice=f'State: {nbrstatus}')
-    elif nbrstate in params['ok_states']:
-        yield Result(state=State.OK, summary=f'State: {nbrstatus}')
-    else:
-        yield Result(state=State.UNKNOWN, notice='Invalid Output from Agent')
+    yield Result(
+        state=State(neighbor_states.get(neighbor.nbrState, 3)),
+        summary=f'Status: {ospf_nbr_state(neighbor.nbrState)}'
+    )
 
     yield Result(state=State.OK, notice=f'Neighbor options: {neighbor.nbrOptions}')
     yield Result(state=State.OK, notice=f'Neighbor priority: {neighbor.nbrPriority}')
@@ -232,9 +247,6 @@ register.check_plugin(
     discovery_function=discovery_ospfv3_neighbor,
     check_function=check_ospfv3_neighbor,
     check_default_parameters={
-        'ok_states': [8, 4],
-        'warning_states': [2, 3, 5, 6, 7],
-        'critical_states': [1],
     },
     check_ruleset_name='ospfv3_neighbor',
 )
diff --git a/agent_based/ospfv3_virtuallink.py b/agent_based/ospfv3_virtuallink.py
index f78aeb3..74c07fc 100644
--- a/agent_based/ospfv3_virtuallink.py
+++ b/agent_based/ospfv3_virtuallink.py
@@ -10,6 +10,7 @@
 # Monitor status of OSPFv3 virtual-links
 #
 # 2021-09-17: rewritten for CMK 2.0
+# 2021-10-02: added WATO options
 #
 # .1.3.6.1.2.1.191.1.11.1.3.3.50529054 = INTEGER: 0
 # .1.3.6.1.2.1.191.1.11.1.4.3.50529054 = Gauge32: 0
@@ -155,27 +156,41 @@ def discovery_ospfv3_virtuallink(section: Dict[str, OspfV3VirtualLink]) -> Disco
 
 
 def check_ospfv3_virtuallink(item, params, section: Dict[str, OspfV3VirtualLink]) -> CheckResult:
+
+    not_found_state = params['state_not_found']
+
+    for virtual_link, alias, NotFoundState in params.get('peer_list', []):
+        if item == virtual_link:
+            yield Result(state=State.OK, summary=f'[{alias}]')
+            not_found_state = NotFoundState
+
     try:
         virtual_link = section[item]
     except KeyError:
-        yield Result(state=State.UNKNOWN, notice='Item not found in SNMP data')
+        yield Result(state=State(not_found_state), notice='Item not found in SNMP data')
         return
 
-    nbrstatus = ospf_nbr_state(virtual_link.VirtNbrState)
+    # default monitoring states for ospfNbrState
+    neighbor_states = {
+        '1': 2,  # down
+        '2': 1,  # attempt
+        '3': 1,  # init
+        '4': 0,  # twoWay
+        '5': 1,  # exchangeStart
+        '6': 1,  # exchange
+        '7': 1,  # loading
+        '8': 0,  # full
+    }
+
+    neighbor_states.update(params.get('neighbor_states', neighbor_states))  # update neighbor_states with params
 
     yield Result(state=State.OK, summary=f'Neighbor ID: {virtual_link.VirtNbrId}')
     yield Result(state=State.OK, summary=f'Area: {virtual_link.VirtNbrArea}')
 
-    nbrstate = virtual_link.VirtNbrState
-
-    if nbrstate in params['critical_states']:
-        yield Result(state=State.CRIT, notice='State: {nbrstatus}')
-    elif nbrstate in params['warning_states']:
-        yield Result(state=State.WARN, notice=f'State: {nbrstatus}')
-    elif nbrstate in params['ok_states']:
-        yield Result(state=State.OK, summary=f', State: {nbrstatus}')
-    else:
-        yield Result(state=State.UNKNOWN, notice='Invalid Output from Agent')
+    yield Result(
+        state=State(neighbor_states.get(virtual_link.VirtNbrState, 3)),
+        summary=f'Status: {ospf_nbr_state(virtual_link.VirtNbrState)}'
+    )
 
     yield Result(state=State.OK, notice=f'Virtual link options: {virtual_link.VirtNbrOptions}')
     yield Result(state=State.OK, notice=f'Virtual link hello suppressed: {virtual_link.VirtNbrHelloSuppressed}')
@@ -228,9 +243,6 @@ register.check_plugin(
     discovery_function=discovery_ospfv3_virtuallink,
     check_function=check_ospfv3_virtuallink,
     check_default_parameters={
-        'ok_states': [8, 4],
-        'warning_states': [2, 3, 5, 6, 7],
-        'critical_states': [1],
     },
     check_ruleset_name='ospfv3_virtuallink',
 )
diff --git a/ospfv3.mkp b/ospfv3.mkp
index e46832ab2faabdf1ed8b4d742e190900e05650fa..5ad8fcccb6f6edaf3119ad1e22956d931158ef85 100644
GIT binary patch
literal 13187
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

literal 9626
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

diff --git a/packages/ospfv3 b/packages/ospfv3
index 5ac9a2f..be7a5c4 100644
--- a/packages/ospfv3
+++ b/packages/ospfv3
@@ -7,11 +7,11 @@
                            'ospfv3_neighbor.py',
                            'ospfv3_virtuallink.py',
                            'utils/ospfv3.py'],
-           'web': ['plugins/metrics/ospfv3.py']},
+           'web': ['plugins/metrics/ospfv3.py', 'plugins/wato/ospfv3.py']},
  'name': 'ospfv3',
- 'num_files': 7,
+ 'num_files': 8,
  'title': 'Collection of OSPFv3 checks',
- 'version': '20210917.v0.2',
+ 'version': '20211002.v0.3',
  'version.min_required': '2.0.0',
- 'version.packaged': '2021.07.14',
+ 'version.packaged': '2021.09.20',
  'version.usable_until': None}
\ No newline at end of file
diff --git a/web/plugins/metrics/ospfv3.py b/web/plugins/metrics/ospfv3.py
index 58e9e6c..0cb2beb 100644
--- a/web/plugins/metrics/ospfv3.py
+++ b/web/plugins/metrics/ospfv3.py
@@ -46,7 +46,7 @@ metric_info['ospfv3_events'] = {
     'color': '26/a',
 }
 metric_info['ospfv3_lsretransqlen'] = {
-    'title': _('queue length'),
+    'title': _('Queue length'),
     'unit': 'count',
     'color': '16/a',
 }
diff --git a/web/plugins/wato/ospfv3.py b/web/plugins/wato/ospfv3.py
new file mode 100644
index 0000000..b6a632e
--- /dev/null
+++ b/web/plugins/wato/ospfv3.py
@@ -0,0 +1,370 @@
+#!/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-09-28
+#
+# wato plugin for ospfv3_neighbor check
+#
+#
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    TextAscii,
+    ListOf,
+    Tuple,
+    TextUnicode,
+    MonitoringState,
+    FixedValue,
+)
+
+from cmk.gui.plugins.wato import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+    RulespecGroupCheckParametersDiscovery,
+    HostRulespec,
+)
+
+neighbor_states = ('neighbor_states',
+                   Dictionary(
+                       title=_('State to report for OSPF neighbor state'),
+                       help=_('Map each OSPF state to a CheckMK monitoring state'),
+                       elements=[
+                           ('1',
+                            MonitoringState(
+                                title=_('1 - down'),
+                                help=_(
+                                    'This is the first OSPF neighbor state. It means that no information (hellos) has '
+                                    'been received from this neighbor, but hello packets can still be sent to the '
+                                    'neighbor in this state. During the fully adjacent neighbor state, if a router '
+                                    'doesn\'t receive hello packet from a neighbor within the RouterDeadInterval time '
+                                    '(RouterDeadInterval = 4*HelloInterval by default) or if the manually configured '
+                                    'neighbor is being removed from the configuration, then the neighbor state changes '
+                                    'from Full to Down. Default monitoring state is "CRIT"'),
+                                default_value=2,
+                            )),
+                           ('2',
+                            MonitoringState(
+                                title=_('2 - attempt'),
+                                help=_(
+                                    'This state is only valid for manually configured neighbors in an NBMA '
+                                    'environment. In Attempt state, the router sends unicast hello packets every poll '
+                                    'interval to the neighbor, from which hellos have not been received within the '
+                                    'dead interval. Default monitoring state is "WARN"'),
+                                default_value=1,
+                            )),
+                           ('3',
+                            MonitoringState(
+                                title=_('3 - init'),
+                                help=_(
+                                    'This state specifies that the router has received a hello packet from its '
+                                    'neighbor, but the receiving router\'s ID was not included in the hello packet. '
+                                    'When a router receives a hello packet from a neighbor, it should list the '
+                                    'sender\'s router ID in its hello packet as an acknowledgment that it received a '
+                                    'valid hello packet. Default monitoring state is "WARN"'),
+                                default_value=1,
+                            )),
+                           ('4',
+                            MonitoringState(
+                                title=_('4 - twoWay'),
+                                help=_(
+                                    'This state designates that bi-directional communication has been established '
+                                    'between two routers. Bi-directional means that each router has seen the other\'s '
+                                    'hello packet. This state is attained when the router receiving the hello packet '
+                                    'sees its own Router ID within the received hello packet\'s neighbor field. At '
+                                    'this state, a router decides whether to become adjacent with this neighbor. On '
+                                    'broadcast media and non-broadcast multiaccess networks, a router becomes full '
+                                    'only with the designated router (DR) and the backup designated router (BDR); it '
+                                    'stays in the 2-way state with all other neighbors. On Point-to-point and '
+                                    'Point-to-multipoint networks, a router becomes full with all connected routers. '
+                                    'At the end of this stage, the DR and BDR for broadcast and non-broadcast '
+                                    'multiacess networks are elected. For more information on the DR election process, '
+                                    'refer to DR Election. Note: Receiving a Database Descriptor (DBD) packet from a '
+                                    'neighbor in the init state will also a cause a transition to 2-way state. Default '
+                                    'monitoring state is "OK"'),
+                                default_value=0,
+                            )),
+                           ('5',
+                            MonitoringState(
+                                title=_('5 - exchangeStart'),
+                                help=_('Once the DR and BDR are elected, the actual process of exchanging link state '
+                                       'information can start between the routers and their DR and BDR. In this state, '
+                                       'the routers and their DR and BDR establish a master-slave relationship and '
+                                       'choose the initial sequence number for adjacency formation. The router with '
+                                       'the higher router ID becomes the master and starts the exchange, and as such, '
+                                       'is the only router that can increment the sequence number. Note that one would '
+                                       'logically conclude that the DR/BDR with the highest router ID will become the '
+                                       'master during this process of master-slave relation. Remember that the DR/BDR '
+                                       'election might be purely by virtue of a higher priority configured on the '
+                                       'router instead of highest router ID. Thus, it is possible that a DR plays the '
+                                       'role of slave. And also note that master/slave election is on a per-neighbor '
+                                       'basis. Default monitoring state is "WARN"'),
+                                default_value=1,
+                            )),
+                           ('6',
+                            MonitoringState(
+                                title=_('6 - exchange'),
+                                help=_(
+                                    'In the exchange state, OSPF routers exchange database descriptor (DBD) packets. '
+                                    'Database descriptors contain link-state advertisement (LSA) headers only and '
+                                    'describe the contents of the entire link-state database. Each DBD packet has a '
+                                    'sequence number which can be incremented only by master which is explicitly '
+                                    'acknowledged by slave. Routers also send link-state request packets and '
+                                    'link-state update packets (which contain the entire LSA) in this state. The '
+                                    'contents of the DBD received are compared to the information contained in the '
+                                    'routers link-state database to check if new or more current link-state '
+                                    'information is available with the neighbor. Default monitoring state is "WARN"'),
+                                default_value=1,
+                            )),
+                           ('7',
+                            MonitoringState(
+                                title=_('7 - loading'),
+                                help=_(
+                                    'In this state, the actual exchange of link state information occurs. Based on the '
+                                    'information provided by the DBDs, routers send link-state request packets. The '
+                                    'neighbor then provides the requested link-state information in link-state update '
+                                    'packets. During the adjacency, if a router receives an outdated or missing LSA, '
+                                    'it requests that LSA by sending a link-state request packet. All link-state '
+                                    'update packets are acknowledged. Default monitoring state is "WARN"'),
+                                default_value=1,
+                            )),
+                           ('8',
+                            MonitoringState(
+                                title=_('8 - full'),
+                                help=_('In this state, routers are fully adjacent with each other. All the router and '
+                                       'network LSAs are exchanged and the routers databases are fully synchronized. '
+                                       'Full is the normal state for an OSPF router. If a router is stuck in another '
+                                       'state, it\'s an indication that there are problems in forming adjacencies. The '
+                                       'only exception to this is the 2-way state, which is normal in a broadcast '
+                                       'network. Routers achieve the full state with their DR and BDR only. Neighbors '
+                                       'always see each other as 2-way. Default monitoring state is "OK"'),
+                                default_value=0,
+                            )),
+                       ]))
+
+
+# #####################################################
+#
+# OSPFv3 General
+#
+# #####################################################
+
+
+def _parameter_valuespec_ospfv3_general():
+    return Dictionary(
+        elements=[
+            ('state_admin_disabled',
+             MonitoringState(
+                 title=_('State to report if OSPFv3 is admin disabled'),
+                 help=_('Monitoring state if the OSPFv3 process is admin disabled. Default state is "WARNING"'),
+                 default_value=1,
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='ospfv3_general',
+        group=RulespecGroupCheckParametersNetworking,
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_ospfv3_general,
+        title=lambda: _('OSPFv3 general'),
+    ))
+
+
+def _valuespec_discovery_ospfv3_general():
+    return Dictionary(
+            title=_('OSPFv3 general'),
+            elements=[
+                ('admin_disabled',
+                 FixedValue(
+                     True,
+                     title=_('discover admin disabled OSPFv3 process'),
+                     totext=_('discover admin disabled OSPFv3 process'),
+                     default_value=False,
+                 )),
+            ],
+        )
+
+
+rulespec_registry.register(
+    HostRulespec(
+        group=RulespecGroupCheckParametersDiscovery,
+        match_type='dict',
+        name='discovery_ospfv3_general',
+        valuespec=_valuespec_discovery_ospfv3_general,
+    ))
+
+
+# #####################################################
+#
+# OSPFv3 Interface
+#
+# #####################################################
+
+
+def _parameter_valuespec_ospfv3_interface():
+    return Dictionary(
+        elements=[
+            ('state_admin_disabled',
+             MonitoringState(
+                 title=_('State to report if OSPFv3 is admin disabled'),
+                 help=_('Monitoring state if OSPFv3 is admin disabled. Default state is "WARNING"'),
+                 default_value=1,
+             )),
+            ('state_if_down',
+             MonitoringState(
+                 title=_('State to report if OSPFv3 is down'),
+                 help=_('Monitoring state if OSPFv3 is down. Default state is "CRITICAL"'),
+                 default_value=2,
+             )),
+            ('state_if_wait_stby',
+             MonitoringState(
+                 title=_('State to report if OSPFv3 is in waiting or standby'),
+                 help=_('Monitoring state if OSPFv3 is waiting/standby. Default state is "WARNING"'),
+                 default_value=1,
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='ospfv3_interface',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('OSPFv3 interface'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_ospfv3_interface,
+        title=lambda: _('OSPFv3 interface'),
+    ))
+
+
+# #####################################################
+#
+# OSPFv3 neighbor
+#
+# #####################################################
+
+
+def _parameter_valuespec_ospfv3_neighbor():
+    return Dictionary(
+        elements=[
+            ('state_not_found',
+             MonitoringState(
+                 title=_('State to report if neighbor not found'),
+                 help=_('Default monitoring state if the neighbor is not found in the SNMP data. '
+                        'Default state is "UNKNOWN"'),
+                 default_value=3,
+             )),
+            neighbor_states,
+            ('peer_list',
+             ListOf(
+                 Tuple(
+                     title=_('Neighbors'),
+                     elements=[
+                         TextUnicode(
+                             title=_('OSPFv3 Neighbor'),
+                             help=_(
+                                 'The configured value must match a OSPFv3 Neighbor item reported by the monitored '
+                                 'device. For example: "FE80::192:168:10:148 on Vlan1"'),
+                             allow_empty=False,
+                         ),
+                         TextUnicode(
+                             title=_('OSPFv3 Neighbor Alias'),
+                             help=_('You can configure an individual alias here for the OSPF Neighbor matching '
+                                    'the text configured in the "OSPFv3 Neighbor" field. The alias will '
+                                    'be shown in the check info (i.e. [your alias])'),
+                             allow_empty=False,
+                         ),
+                         MonitoringState(
+                             default_value=2,
+                             title=_('State if not found'),
+                             help=_('You can configure an individual state if the OSPFv3 Neighbor matching the text '
+                                    'configured in the "OSPFv3 Neighbor" field is not found. '
+                                    'Default state is "CRITICAL".')
+                         )]),
+                 add_label=_('Add OSPFv3 Neighbor'),
+                 movable=False,
+                 title=_('Neighbor specific configuration'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='ospfv3_neighbor',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('OSPFv3 Neighbor'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_ospfv3_neighbor,
+        title=lambda: _('OSPFv3 neighbor'),
+    ))
+
+
+# #####################################################
+#
+# OSPFv3 virtual link
+#
+# #####################################################
+
+
+def _parameter_valuespec_ospfv3_virtuallink():
+    return Dictionary(
+        elements=[
+            ('state_not_found',
+             MonitoringState(
+                 title=_('State to report if virtual link not found'),
+                 help=_('Default monitoring state if the virtual link is not found in the SNMP data. '
+                        'Default monitoring state is "UNKNOWN"'),
+                 default_value=3,
+             )),
+            neighbor_states,
+            ('peer_list',
+             ListOf(
+                 Tuple(
+                     title=_('Virtual Link'),
+                     elements=[
+                         TextUnicode(
+                             title=_('OSPFv3 Virtual-Link'),
+                             help=_(
+                                 'The configured value must match a OSPFv3 Virtual-Link item reported by the monitored '
+                                 'device. For example: "2003::192:168:0:1"'),
+                             allow_empty=False,
+                         ),
+                         TextUnicode(
+                             title=_('OSPFv3 Virtual-Link Alias'),
+                             help=_('You can configure an individual alias here for the OSPFv3 Virtual-Link matching '
+                                    'the text configured in the "OSPFv3 Virtual-Link" field. The alias will '
+                                    'be shown in the check info (i.e. [your alias])'),
+                             allow_empty=False,
+                         ),
+                         MonitoringState(
+                             default_value=2,
+                             title=_('State if not found'),
+                             help=_('You can configure an individual state if the OSPFv3 Virtual-Link matching the '
+                                    'text configured in the "OSPFv3 Virtual-Link" field is not found. '
+                                    'Default state is "CRITICAL".')
+                         )]),
+                 add_label=_('Add Virtual-Link'),
+                 movable=False,
+                 title=_('Virtual-Link specific configuration'),
+             )),
+        ],
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='ospfv3_virtuallink',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('OSPFv3 virtual link'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_ospfv3_virtuallink,
+        title=lambda: _('OSPFv3 virtual link'),
+    ))
-- 
GitLab