From 5cc8b760abece886413d3ca38538ab9c23e76a2f Mon Sep 17 00:00:00 2001
From: "th.l" <thl-cmk@outlook.com>
Date: Tue, 3 Aug 2021 09:51:35 +0200
Subject: [PATCH] update project

---
 agent_based/cisco_eigrp_as_info.py            | 324 ++++++++++++
 agent_based/cisco_eigrp_interface.py          | 423 +++++++++++++++
 agent_based/cisco_eigrp_peers.py              | 361 +++++++++++++
 agent_based/cisco_eigrp_topology_table.py     | 488 ++++++++++++++++++
 cisco_eigrp.mkp                               | Bin 15338 -> 14416 bytes
 packages/cisco_eigrp                          |  29 +-
 web/plugins/metrics/cisco_eigrp.py            | 358 +++++--------
 web/plugins/wato/cisco_eigrp_interface.py     |  62 ++-
 web/plugins/wato/cisco_eigrp_peers.py         |  80 ++-
 .../wato/cisco_eigrp_topology_table.py        |  57 +-
 10 files changed, 1887 insertions(+), 295 deletions(-)
 create mode 100644 agent_based/cisco_eigrp_as_info.py
 create mode 100644 agent_based/cisco_eigrp_interface.py
 create mode 100644 agent_based/cisco_eigrp_peers.py
 create mode 100644 agent_based/cisco_eigrp_topology_table.py

diff --git a/agent_based/cisco_eigrp_as_info.py b/agent_based/cisco_eigrp_as_info.py
new file mode 100644
index 0000000..dbb2b15
--- /dev/null
+++ b/agent_based/cisco_eigrp_as_info.py
@@ -0,0 +1,324 @@
+#!/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-17-20
+#
+# Monitor status of Cisco EIGRP AS info
+#
+# 2018-02-11: removed unnecessary OIDs
+# 2018-08-06: modified scan function
+# 2019-10-16: added support for IPv6 and VRFs, added parser function
+#
+#
+# snmpwalk sample
+#
+# thl@surfbox-ii:~$ snmpwalk -v2c -c router-01 -ObentU simulant .1.3.6.1.4.1.9.9.449.1.2.1.1
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.2.65536.10 = Gauge32: 3
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.3.65536.10 = Counter32: 37436
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.4.65536.10 = Counter32: 32170
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.5.65536.10 = Counter32: 161
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.6.65536.10 = Counter32: 143
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.7.65536.10 = Counter32: 14
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.8.65536.10 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.9.65536.10 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.10.65536.10 = Counter32: 14
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.11.65536.10 = Counter32: 143
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.12.65536.10 = Counter32: 132
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.13.65536.10 = Gauge32: 2
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.14.65536.10 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.15.65536.10 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.16.65536.10 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.17.65536.10 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.18.65536.10 = Hex-STRING: 0A A7 DC FF # can be also in the form of "10.10.10.10" :-(
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.19.65536.10 = Counter32: 10
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.20.65536.10 = Counter64: 1
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.21.65536.10 = Counter64: 135
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.22.65536.10 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.2.1.1.23.65536.10 = Gauge32: 0
+
+#
+# sample info
+# [
+#  [u'65536.10', u'1', u'7081', u'6637', u'37', u'45', u'0', u'0', u'0', u'0', u'26', u'32', u'2', u'0', u'0', u'0', u'1', u'\n\xa7\xdc\xfd', u'10', u'0']
+# ]
+#
+
+#
+from time import time
+from dataclasses import dataclass
+from typing import Optional, List
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    Result,
+    check_levels,
+    State,
+    SNMPTree,
+    all_of,
+    contains,
+    exists,
+    OIDEnd,
+    Metric,
+    get_rate,
+    get_value_store,
+    GetRateError,
+    IgnoreResultsError,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+_InetAddressType = {0: 'unknown',
+                   1: 'ipv4',
+                   2: 'ipv6',
+                   3: 'ipv4z',
+                   4: 'ipv6z',
+                   16: 'dns',
+                   }
+
+
+def _render_ip_address(bytestring):
+    return ".".join(["%s" % ord(m) for m in bytestring])
+
+###########################################################################
+#
+#  DATA Parser function
+#
+###########################################################################
+
+
+def parse_cisco_eigrp_as_info(string_table: List[StringTable]):
+    ASInfoTable = []
+    ASTable = {}
+    ASInfo, VrfInfo = string_table
+
+    for OID_END, cEigrpNbrCount, cEigrpHellosSent, cEigrpHellosRcvd, cEigrpUpdatesSent, cEigrpUpdatesRcvd, cEigrpQueriesSent, \
+    cEigrpQueriesRcvd, cEigrpRepliesSent, cEigrpRepliesRcvd, cEigrpAcksSent, cEigrpAcksRcvd, cEigrpInputQHighMark, cEigrpInputQDrops, \
+    cEigrpSiaQueriesSent, cEigrpSiaQueriesRcvd, cEigrpAsRouterIdType, cEigrpAsRouterId, cEigrpTopoRoutes, cEigrpXmitPendReplies in ASInfo:
+
+        cEigrpVrfId = int(OID_END.split('.')[0])
+        cEigrpAS = OID_END.split('.')[1]
+
+        cEigrpVrfName = ''
+        for VrfId, VrfName in VrfInfo:
+            if int(VrfId) == cEigrpVrfId:
+                cEigrpVrfName = VrfName
+        if cEigrpVrfId < 100000:
+            cEigrpAddrFammily = 'IPv4'
+        else:
+            cEigrpAddrFammily = 'IPv6'
+
+        if int(cEigrpAsRouterIdType) == 1:
+            if len(cEigrpAsRouterId) == 4:
+                cEigrpAsRouterId = _render_ip_address(cEigrpAsRouterId)
+
+        ASInfoTable.append({
+            'cEigrpAS': cEigrpAS,
+            'cEigrpVrfName': cEigrpVrfName,
+            'cEigrpVrfId': cEigrpVrfId,
+            'cEigrpAddrFammily': cEigrpAddrFammily,
+            'cEigrpNbrCount': int(cEigrpNbrCount),
+            'cEigrpHellosSent': int(cEigrpHellosSent),
+            'cEigrpHellosRcvd': int(cEigrpHellosRcvd),
+            'cEigrpUpdatesSent': int(cEigrpUpdatesSent),
+            'cEigrpUpdatesRcvd': int(cEigrpUpdatesRcvd),
+            'cEigrpQueriesSent': int(cEigrpQueriesSent),
+            'cEigrpQueriesRcvd': int(cEigrpQueriesRcvd),
+            'cEigrpRepliesSent': int(cEigrpRepliesSent),
+            'cEigrpRepliesRcvd': int(cEigrpRepliesRcvd),
+            'cEigrpAcksSent': int(cEigrpAcksSent),
+            'cEigrpAcksRcvd': int(cEigrpAcksRcvd),
+            'cEigrpInputQHighMark': int(cEigrpInputQHighMark),
+            'cEigrpInputQDrops': int(cEigrpInputQDrops),
+            'cEigrpSiaQueriesSent': int(cEigrpSiaQueriesSent),
+            'cEigrpSiaQueriesRcvd': int(cEigrpSiaQueriesRcvd),
+            'cEigrpAsRouterId': cEigrpAsRouterId,
+            'cEigrpTopoRoutes': int(cEigrpTopoRoutes),
+            'cEigrpXmitPendReplies': int(cEigrpXmitPendReplies),
+        })
+
+        if cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv4':
+            ASTable.update({cEigrpVrfId: {'ServiceText': cEigrpAS, 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv6':
+            ASTable.update({cEigrpVrfId:{'ServiceText': '%s IPv6' % cEigrpAS, 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv4':
+            ASTable.update({cEigrpVrfId:{'ServiceText': '%s VRF %s' % (cEigrpAS, cEigrpVrfName), 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv6':
+            ASTable.update({cEigrpVrfId:{'ServiceText': '%s IPv6 VRF %s' % (cEigrpAS, cEigrpVrfName), 'cEigrpVrfId': cEigrpVrfId}})
+    return [ASTable, ASInfoTable]
+
+###########################################################################
+#
+#  INVENTORY function
+#
+###########################################################################
+
+
+def discovery_cisco_eigrp_as_info(section) -> DiscoveryResult:
+    ASTable, ASInfoTable = section
+    ASTable = dict(ASTable)
+    for Key in ASTable.keys():
+        ServiceText = ASTable.get(Key).get('ServiceText')
+        yield Service(item=ServiceText)
+
+###########################################################################
+#
+#  CHECK function
+#
+###########################################################################
+
+
+def check_cisco_eigrp_as_info(item, params, section) -> CheckResult:
+    ASTable, ASInfoTable = section
+    ASTable = dict(ASTable)
+
+    cEigrpVrfId = ''
+    for Key in ASTable.keys():
+        ServiceText = ASTable.get(Key).get('ServiceText')
+        if ServiceText == item:
+            cEigrpVrfId = ASTable.get(Key).get('cEigrpVrfId')
+
+    if cEigrpVrfId != '':
+        for AS in ASInfoTable:
+            if AS.get('cEigrpVrfId') == cEigrpVrfId:
+                cEigrpNbrCount = AS.get('cEigrpNbrCount')
+                cEigrpHellosSent = AS.get('cEigrpHellosSent')
+                cEigrpHellosRcvd = AS.get('cEigrpHellosRcvd')
+                cEigrpUpdatesSent = AS.get('cEigrpUpdatesSent')
+                cEigrpUpdatesRcvd = AS.get('cEigrpUpdatesRcvd')
+                cEigrpQueriesSent = AS.get('cEigrpQueriesSent')
+                cEigrpQueriesRcvd = AS.get('cEigrpQueriesRcvd')
+                cEigrpRepliesSent = AS.get('cEigrpRepliesSent')
+                cEigrpRepliesRcvd = AS.get('cEigrpRepliesRcvd')
+                cEigrpAcksSent = AS.get('cEigrpAcksSent')
+                cEigrpAcksRcvd = AS.get('cEigrpAcksRcvd')
+                cEigrpInputQHighMark = AS.get('cEigrpInputQHighMark')
+                cEigrpInputQDrops = AS.get('cEigrpInputQDrops')
+                cEigrpSiaQueriesSent = AS.get('cEigrpSiaQueriesSent')
+                cEigrpSiaQueriesRcvd = AS.get('cEigrpSiaQueriesRcvd')
+                cEigrpAsRouterId = AS.get('cEigrpAsRouterId')
+                cEigrpTopoRoutes = AS.get('cEigrpTopoRoutes')
+                cEigrpXmitPendReplies = AS.get('cEigrpXmitPendReplies')
+
+                yield Result(
+                    state=State.OK,
+                    summary=f'Router-ID: {cEigrpAsRouterId}, neighbors: {cEigrpNbrCount}, Routes in topologie table: {cEigrpTopoRoutes}')
+
+                for key, value in [
+                            ('cEigrpNbrCount', cEigrpNbrCount),
+                            ('cEigrpUpdatesSent', cEigrpUpdatesSent),
+                            ('cEigrpUpdatesRcvd', cEigrpUpdatesRcvd),
+                            ('cEigrpQueriesSent', cEigrpQueriesSent),
+                            ('cEigrpQueriesRcvd', cEigrpQueriesRcvd),
+                            ('cEigrpRepliesSent', cEigrpRepliesSent),
+                            ('cEigrpRepliesRcvd', cEigrpRepliesRcvd),
+                            ('cEigrpAcksSent', cEigrpAcksSent),
+                            ('cEigrpAcksRcvd', cEigrpAcksRcvd),
+                            ('cEigrpInputQHighMark', cEigrpInputQHighMark),
+                            ('cEigrpInputQDrops', cEigrpInputQDrops),
+                            ('cEigrpSiaQueriesSent', cEigrpSiaQueriesSent),
+                            ('cEigrpSiaQueriesRcvd', cEigrpSiaQueriesRcvd),
+                            ('cEigrpTopoRoutes', cEigrpTopoRoutes),
+                            ('cEigrpXmitPendReplies', cEigrpXmitPendReplies),
+                ]:
+                    yield Metric(name=f'cisco_eigrp_as_info_{key}', value=value)
+
+                now_time = time()
+                rate_item=item.replace(' ', '_').replace(':', '_')
+                value_store = get_value_store()
+                raise_ingore_res = False
+
+                for key, value in [
+                    ('cEigrpHellosSent', cEigrpHellosSent),
+                    ('cEigrpHellosRcvd', cEigrpHellosRcvd),
+
+                ]:
+                    try:
+                        try:
+                            value = get_rate(
+                                value_store,
+                                f'cisco_eigrp_as_info_{key}.{rate_item}',
+                                now_time,
+                                value,
+                                raise_overflow=False
+                            )
+                        except GetRateError:
+                            raise_ingore_res = True
+                            value = 0
+                        yield Metric(name=f'cisco_eigrp_as_info_{key}', value=value, boundaries=(0, None))
+                    except KeyError:
+                        pass
+
+                if raise_ingore_res:
+                    raise IgnoreResultsError('Initializing counters')
+
+
+###########################################################################
+#
+#  CHECK info
+#
+###########################################################################
+
+
+register.snmp_section(
+    name='cisco_eigrp_as_info',
+    parse_function=parse_cisco_eigrp_as_info,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.2.1.1',  # CISCO-TRUSTSEC-MIB::ctsEnvironmentDataObjects
+            oids=[
+                OIDEnd(),  # AS number
+                '2',  # cEigrpNbrCount        [1]
+                '3',  # cEigrpHellosSent      [2]
+                '4',  # cEigrpHellosRcvd      [3]
+                '5',  # cEigrpUpdatesSent     [4]
+                '6',  # cEigrpUpdatesRcvd     [5]
+                '7',  # cEigrpQueriesSent     [6]
+                '8',  # cEigrpQueriesRcvd     [7]
+                '9',  # cEigrpRepliesSent     [8]
+                '10',  # cEigrpRepliesRcvd     [9]
+                '11',  # cEigrpAcksSent        [10]
+                '12',  # cEigrpAcksRcvd        [11]
+                '13',  # cEigrpInputQHighMark  [12]
+                '14',  # cEigrpInputQDrops     [13]
+                '15',  # cEigrpSiaQueriesSent  [14]
+                '16',  # cEigrpSiaQueriesRcvd  [15]
+                '17',  # cEigrpAsRouterIdType  [16]
+                '18',  # cEigrpAsRouterId      [17]
+                '19',  # cEigrpTopoRoutes      [18]
+                '22',  # cEigrpXmitPendReplies [19]
+                # '20',     # cEigrpHeadSerial    []
+                # '21',     # cEigrpNextSerial    []
+                # '23',     # cEigrpXmitDummies   []
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.1.1.1',  # CISCO-TRUSTSEC-MIB::ctsEnvironmentDataObjects
+            oids=[
+                OIDEnd(),  # VRF ID
+                '2',  # cEigrpVpnName
+            ]
+        ),
+
+    ],
+    detect=all_of(
+        contains('.1.3.6.1.2.1.1.1.0', 'cisco'),  # sysDescr
+        exists('.1.3.6.1.4.1.9.9.449.1.2.1.1.2.*'),  # CISCO-EIGRP-MIB::cEigrpNbrCount
+    ))
+
+register.check_plugin(
+    name='cisco_eigrp_as_info',
+    service_name='EIGRP AS number %s',
+    discovery_function=discovery_cisco_eigrp_as_info,
+    check_function=check_cisco_eigrp_as_info,
+    check_default_parameters={
+    },
+    check_ruleset_name='cisco_eigrp_as_info',
+)
diff --git a/agent_based/cisco_eigrp_interface.py b/agent_based/cisco_eigrp_interface.py
new file mode 100644
index 0000000..fcf25df
--- /dev/null
+++ b/agent_based/cisco_eigrp_interface.py
@@ -0,0 +1,423 @@
+#!/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-17-21
+#
+# Monitor status of Cisco EIGRP interface info
+#
+# 2018-01-23: Th.L.: inventory skip Loopback interface
+# 2018-02-11: Th.L.: removed unnecessary OIDs
+# 2018-08-06: modified scan function
+# 2019-10-14: added support for hamc-sha-256 authentication, md5 moved to warn, none moved to crit
+# 2019-10-16: added support for IPv6 and VRFs, added data parser function
+# 2019-10-31: changed item from interface long-name to interface short name
+#
+# snmpwalk sample
+#
+# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c router-01 simulant .1.3.6.1.4.1.9.9.449.1.5.1.1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.3.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.3.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.3.65536.10.8 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.3.65536.10.9 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.4.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.4.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.4.65536.10.8 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.4.65536.10.9 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.5.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.5.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.5.65536.10.8 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.5.65536.10.9 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.6.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.6.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.6.65536.10.8 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.6.65536.10.9 = Gauge32: 19
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.7.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.7.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.7.65536.10.8 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.7.65536.10.9 = Gauge32: 23
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.8.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.8.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.8.65536.10.8 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.8.65536.10.9 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.9.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.9.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.9.65536.10.8 = Gauge32: 50
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.9.65536.10.9 = Gauge32: 84
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.10.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.10.65536.10.7 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.10.65536.10.8 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.10.65536.10.9 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.11.65536.10.1 = Gauge32: 5
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.11.65536.10.7 = Gauge32: 5
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.11.65536.10.8 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.11.65536.10.9 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.12.65536.10.1 = Counter64: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.12.65536.10.7 = Counter64: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.12.65536.10.8 = Counter64: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.12.65536.10.9 = Counter64: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.13.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.13.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.13.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.13.65536.10.9 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.14.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.14.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.14.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.14.65536.10.9 = Counter32: 18
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.15.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.15.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.15.65536.10.8 = Counter32: 64
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.15.65536.10.9 = Counter32: 40
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.16.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.16.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.16.65536.10.8 = Counter32: 66
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.16.65536.10.9 = Counter32: 27
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.17.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.17.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.17.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.17.65536.10.9 = Counter32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.18.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.18.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.18.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.18.65536.10.9 = Counter32: 2
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.19.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.19.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.19.65536.10.8 = Counter32: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.19.65536.10.9 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.20.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.20.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.20.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.20.65536.10.9 = Counter32: 5
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.21.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.21.65536.10.7 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.21.65536.10.8 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.21.65536.10.9 = Counter32: 3
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.22.65536.10.1 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.22.65536.10.7 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.22.65536.10.8 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.22.65536.10.9 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.23.65536.10.1 = ""
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.23.65536.10.7 = ""
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.23.65536.10.8 = STRING: "KEY-EIGRP-10"
+# .1.3.6.1.4.1.9.9.449.1.5.1.1.23.65536.10.9 = STRING: "KEY-EIGRP-10"
+# #
+# sample info
+# [
+#  [
+#   [u'65536.10.1', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'5', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'1', u''],
+#   [u'65536.10.7', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'5', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'0', u'1', u''],
+#   [u'65536.10.8', u'1', u'0', u'0', u'1', u'0', u'0', u'50', u'0', u'1', u'0', u'0', u'0', u'64', u'66', u'0', u'0', u'1', u'0', u'0', u'2', u'KEY-EIGRP-10'],
+#   [u'65536.10.9', u'1', u'0', u'0', u'19', u'23', u'0', u'84', u'0', u'1', u'0', u'0', u'18', u'40', u'27', u'1', u'2', u'0', u'5', u'3', u'2', u'KEY-EIGRP-10']
+#  ],
+#  [
+#   [u'1', u'GigabitEthernet0/0/0'],
+#   [u'2', u'GigabitEthernet0/0/1'],
+#   [u'3', u'GigabitEthernet0/0/2'],
+#   [u'4', u'GigabitEthernet0/0/3'],
+#   [u'5', u'GigabitEthernet0'],
+#   [u'6', u'Null0'],
+#   [u'7', u'Loopback0'],
+#   [u'8', u'Tunnel10'],
+#   [u'9', u'Tunnel101']
+#  ]
+# ]
+#
+
+from time import mktime, gmtime
+from dataclasses import dataclass
+from typing import Optional, List, Dict
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    Result,
+    check_levels,
+    State,
+    SNMPTree,
+    all_of,
+    contains,
+    exists,
+    OIDEnd,
+    Metric,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+
+@dataclass
+class EigrpInterface:
+    cEigrpVrfId: int
+    cEigrpAS: str
+    cEigrpVrfName: str
+    cEigrpIfName: str
+    cEigrpPeerCount: int
+    cEigrpXmitReliableQ: int
+    cEigrpXmitUnreliableQ: int
+    cEigrpMeanSrtt: int
+    cEigrpPendingRoutes: int
+    cEigrpHelloInterval: int
+    cEigrpUMcasts: int
+    cEigrpUUcasts: int
+    cEigrpRUcasts: int
+    cEigrpMcastExcepts: int
+    cEigrpCRpkts: int
+    cEigrpAcksSuppressed: int
+    cEigrpRetransSent: int
+    cEigrpOOSrvcd: int
+    cEigrpAuthMode: str
+    cEigrpAuthKeyChain: str
+
+
+_InetAddressType = {
+    0: 'unknown',
+    1: 'ipv4',
+    2: 'ipv6',
+    3: 'ipv4z',
+    4: 'ipv6z',
+    16: 'dns',
+}
+
+
+def _eigrp_authmode(mode: int) -> str:
+    name = {
+        0: 'unknown',
+        1: 'none',
+        2: 'md5',
+        3: 'hmac-sha-256'
+    }
+    return name.get(mode, f'unknown {mode}')
+
+
+def _get_short_if_name(st: str) -> str:
+    names = {
+        'ethernet': 'Eth',
+        'fastethernet': 'Fa',
+        'gigabitethernet': 'Gi',
+        'tengigabitethernet': 'Te',
+        'fortygigabitethernet': 'Fo',
+        'hundredgigabitethernet': 'Hu',
+        'port-channel': 'Po',
+        'tunnel': 'Tu',
+        'loopback': 'Lo',
+    }
+    for item in names.keys():
+        if st.lower().startswith(item):
+            st = st.lower().replace(item, names.get(item))
+    return st
+
+###########################################################################
+#
+#  DATA Parser function
+#
+###########################################################################
+
+
+def parse_cisco_eigrp_interface(string_table: List[StringTable]) -> Dict[str, EigrpInterface]:
+    EigrpInterfaces, InterfaceNames, VrfInfo = string_table
+    EigrpIfTable = {}
+
+    for OID_END, cEigrpPeerCount, cEigrpXmitReliableQ, cEigrpXmitUnreliableQ, cEigrpMeanSrtt, cEigrpPendingRoutes, \
+        cEigrpHelloInterval, cEigrpUMcasts, cEigrpRMcasts, cEigrpUUcasts, cEigrpRUcasts, cEigrpMcastExcepts, \
+        cEigrpCRpkts, cEigrpAcksSuppressed, cEigrpRetransSent, cEigrpOOSrvcd, cEigrpAuthMode, \
+        cEigrpAuthKeyChain in EigrpInterfaces:
+        
+        cEigrpVrfId = int(OID_END.split('.')[0])
+        cEigrpAS = OID_END.split('.')[1]
+        cEigrpIfIndex = int(OID_END.split('.')[2])
+        cEigrpIfName = ''
+        for ifindex, ifname, iftype in InterfaceNames:
+            if int(ifindex) == cEigrpIfIndex:  # compare interface index
+                if not int(iftype) == 24:  # skip Loopback interfaces
+                    cEigrpIfName = _get_short_if_name(ifname)
+                    
+        if cEigrpIfName != '':
+            cEigrpVrfName = ''
+            for VrfId, VrfName in VrfInfo:
+                if int(VrfId) == cEigrpVrfId:
+                    cEigrpVrfName = VrfName
+
+            if cEigrpVrfId < 100000:
+                cEigrpAddrFammily = 'IPv4'
+            else:
+                cEigrpAddrFammily = 'IPv6'
+            
+            ServiceText = ''
+            if cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv4':
+                ServiceText = f'{cEigrpIfName} on AS {cEigrpAS}'
+            elif cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv6':
+                ServiceText = f'{cEigrpIfName} on AS {cEigrpAS} IPv6'
+            elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv4':
+                ServiceText = f'{cEigrpIfName} on AS {cEigrpAS} VRF {cEigrpVrfName}'
+            elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv6':
+                ServiceText = f'{cEigrpIfName} on AS {cEigrpAS} IPv6 VRF {cEigrpVrfName}'
+
+            EigrpIfTable[ServiceText] = EigrpInterface(
+                cEigrpVrfId=cEigrpVrfId,
+                cEigrpAS=cEigrpAS,
+                cEigrpVrfName=cEigrpVrfName,
+                cEigrpIfName=cEigrpIfName,
+                cEigrpPeerCount=int(cEigrpPeerCount),
+                cEigrpXmitReliableQ=int(cEigrpXmitReliableQ),
+                cEigrpXmitUnreliableQ=int(cEigrpXmitUnreliableQ),
+                cEigrpMeanSrtt=int(cEigrpMeanSrtt),
+                cEigrpPendingRoutes=int(cEigrpPendingRoutes),
+                cEigrpHelloInterval=int(cEigrpHelloInterval),
+                cEigrpUMcasts=int(cEigrpUMcasts),
+                cEigrpUUcasts=int(cEigrpUUcasts),
+                cEigrpRUcasts=int(cEigrpRUcasts),
+                cEigrpMcastExcepts=int(cEigrpMcastExcepts),
+                cEigrpCRpkts=int(cEigrpCRpkts),
+                cEigrpAcksSuppressed=int(cEigrpAcksSuppressed),
+                cEigrpRetransSent=int(cEigrpRetransSent),
+                cEigrpOOSrvcd=int(cEigrpOOSrvcd),
+                cEigrpAuthMode=_eigrp_authmode(int(cEigrpAuthMode)),
+                cEigrpAuthKeyChain=cEigrpAuthKeyChain,
+        )
+
+    return EigrpIfTable
+
+###########################################################################
+#
+#  INVENTORY function
+#
+###########################################################################
+
+
+def discovery_cisco_eigrp_interface(section: Dict[str, EigrpInterface]) -> DiscoveryResult:
+    for key in section.keys():
+        yield Service(item=key)
+
+###########################################################################
+#
+#  CHECK function
+#
+###########################################################################
+
+
+def check_cisco_eigrp_interface(item, params, section: Dict[str, EigrpInterface]) -> CheckResult:
+    try:
+        eigrp_if = section[item]
+    except KeyError:
+        return
+
+    interface_type = 0
+
+    yield Result(state=State.OK, summary=f'Peer count: {eigrp_if.cEigrpPeerCount}, Hello interval: {eigrp_if.cEigrpHelloInterval}, Auth Mode: {eigrp_if.cEigrpAuthMode}')
+
+    md5_auth_state = params.get('md5_auth_state')
+    no_auth_state = params.get('no_auth_state')
+    if interface_type not in params.get('ignore_interfaces_auth'):
+        if eigrp_if.cEigrpAuthMode in ['md5'] and md5_auth_state != 0:
+            yield Result(state=State(md5_auth_state), notice='weak authentication set')
+            # yield Result(state=State.OK, notice=f'you can change the authentication mode to hmac-sha-256 by removing the eigrp authentication')
+            # yield Result(state=State.OK, notice=f'configuration from the interface and move it to the "router eigrp configuration"')
+            # yield Result(state=State.OK, notice=f'you need to change to "named mode configuration"')
+            # yield Result(state=State.OK, notice=f'router eigrp YOUR-EIGRP-NAME')
+            # yield Result(state=State.OK, notice=f'  address-family ipv4 unicast autonomous-system {eigrp_if.cEigrpAS}')
+            # yield Result(state=State.OK, notice=f'     af-interface {eigrp_if.cEigrpIfName}')
+            # yield Result(state=State.OK, notice=f'          authentication mode hmac-sha-256 YOUR-EIGRPKEY')
+            # yield Result(state=State.OK, notice=f'     exit-af-interface')
+            # yield Result(state=State.OK, notice=f'     eigrp YOUR-ROUTER-ID')
+            # yield Result(state=State.OK, notice=f'     network ....')
+            # yield Result(state=State.OK, notice=f'end')
+        elif eigrp_if.cEigrpAuthMode == 'none' and no_auth_state != 0:
+            yield Result(state=State(no_auth_state), notice='no authentication set')
+    if eigrp_if.cEigrpAuthKeyChain != '':
+        yield Result(state=State.OK, notice=f'Key chain: {eigrp_if.cEigrpAuthKeyChain}')
+
+    for key, value in [
+        ('cEigrpPeerCount', eigrp_if.cEigrpPeerCount),
+        ('cEigrpXmitReliableQ', eigrp_if.cEigrpXmitReliableQ),
+        ('cEigrpXmitUnreliableQ', eigrp_if.cEigrpXmitUnreliableQ),
+        ('cEigrpMeanSrtt', eigrp_if.cEigrpMeanSrtt),
+        ('cEigrpPendingRoutes', eigrp_if.cEigrpPendingRoutes),
+        # ('cEigrpRMcasts', eigrp_if.cEigrpRMcasts),
+        ('cEigrpUMcasts', eigrp_if.cEigrpUMcasts),
+        ('cEigrpUUcasts', eigrp_if.cEigrpUUcasts),
+        ('cEigrpRUcasts', eigrp_if.cEigrpRUcasts),
+        ('cEigrpMcastExcepts', eigrp_if.cEigrpMcastExcepts),
+        ('cEigrpCRpkts', eigrp_if.cEigrpCRpkts),
+        ('cEigrpAcksSuppressed', eigrp_if.cEigrpAcksSuppressed),
+        ('cEigrpRetransSent', eigrp_if.cEigrpRetransSent),
+        ('cEigrpOOSrvcd', eigrp_if.cEigrpOOSrvcd),
+    ]:
+        yield Metric(name=f'cisco_eigrp_interface_{key}', value=value)
+
+
+###########################################################################
+#
+#  CHECK info
+#
+###########################################################################
+
+
+register.snmp_section(
+    name='cisco_eigrp_interface',
+    parse_function=parse_cisco_eigrp_interface,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.5.1.1',  # CISCO-TRUSTSEC-MIB::ctsEnvironmentDataObjects
+            oids=[
+                OIDEnd(),  # AS number and interface index [0] (u'65536.10.1')
+                '3',  # cEigrpPeerCount               [1]
+                '4',  # cEigrpXmitReliableQ           [2]
+                '5',  # cEigrpXmitUnreliableQ         [3]
+                '6',  # cEigrpMeanSrtt                [4]
+                '10',  # cEigrpPendingRoutes           [5]
+                '11',  # cEigrpHelloInterval           [6]
+                '13',  # cEigrpUMcasts                 [7]
+                '14',  # cEigrpRMcasts                 [8]
+                '15',  # cEigrpUUcasts                 [9]
+                '16',  # cEigrpRUcasts                 [10]
+                '17',  # cEigrpMcastExcepts            [11]
+                '18',  # cEigrpCRpkts                  [12]
+                '19',  # cEigrpAcksSuppressed          [13]
+                '20',  # cEigrpRetransSent             [14]
+                '21',  # cEigrpOOSrvcd                 [15]
+                '22',  # cEigrpAuthMode                [16]
+                '23',  # cEigrpAuthKeyChain            [17]
+                # '7',      # cEigrpPacingReliable          []
+                # '8',      # cEigrpPacingUnreliable        []
+                # '9',      # cEigrpMFlowTimer              []
+                # '12',     # cEigrpXmitNextSerial          []
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.2.1.2.2.1',  #
+            oids=[
+                '1',  # ifIndex
+                '2',  # ifDescr
+                '3',  # ifType
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.1.1.1',  #
+            oids=[
+                OIDEnd(),  # VRF ID
+                '2',  # cEigrpVpnName [0]
+            ]
+        ),
+    ],
+    detect=all_of(
+        contains('.1.3.6.1.2.1.1.1.0', 'cisco'),  # sysDescr
+        exists('.1.3.6.1.4.1.9.9.449.1.5.1.1.3.*'),  # CISCO-EIGRP-MIB::cEigrpPeerCount
+    ))
+
+register.check_plugin(
+    name='cisco_eigrp_interface',
+    service_name='EIGRP interface %s',
+    discovery_function=discovery_cisco_eigrp_interface,
+    check_function=check_cisco_eigrp_interface,
+    check_default_parameters={
+        'ignore_interfaces_auth': [24, ],  # Loopback
+        'no_auth_state': 2,
+        'md5_auth_state': 1,
+    },
+    check_ruleset_name='cisco_eigrp_interface',
+)
diff --git a/agent_based/cisco_eigrp_peers.py b/agent_based/cisco_eigrp_peers.py
new file mode 100644
index 0000000..4183fb4
--- /dev/null
+++ b/agent_based/cisco_eigrp_peers.py
@@ -0,0 +1,361 @@
+#!/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-17-20
+#
+# Monitor status of Cisco EIGRP peers
+#
+# 2018-02-11: removed unnecessary OIDs
+# 2018-07-26: code cleanup, removed hold time from infotext (it is the actual time, not the configured value)
+# 2018-08-06: modified scan function
+# 2019-07-01: fixed uptime for peers up for more then 1 year...
+# 2019-10-15: added initial support for IPv6, code cleanup (parser function)
+# 2019-10-16: added VRF support, fixed ipv4 address rendering
+# 2021-08-02: rewritten for CMK 2.0
+#
+# ToDo: state_peer_not_found, alias, min_uptime_levels in WATO
+#
+#  snmpwalk sample
+#
+# thl@surfbox-ii:~$ snmpwalk -v2c -c router-01 -ObentU simulant .1.3.6.1.4.1.9.9.449.1.4.1.1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.2.65536.10.1 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.2.65536.10.2 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.2.65536.10.3 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.3.65536.10.1 = Hex-STRING: 0A A7 DD 3A   # can be also in the form of "10.10.10.10" :-(
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.3.65536.10.2 = Hex-STRING: 0A A7 DD 39
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.3.65536.10.3 = Hex-STRING: 0A A7 DD 3C
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.4.65536.10.1 = INTEGER: 9
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.4.65536.10.2 = INTEGER: 9
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.4.65536.10.3 = INTEGER: 9
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.5.65536.10.1 = Gauge32: 2
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.5.65536.10.2 = Gauge32: 2
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.5.65536.10.3 = Gauge32: 2
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.6.65536.10.1 = STRING: "01:05:33"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.6.65536.10.2 = STRING: "01:06:06"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.6.65536.10.3 = STRING: "01:05:57"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.7.65536.10.1 = Gauge32: 469
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.7.65536.10.2 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.7.65536.10.3 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.8.65536.10.1 = Gauge32: 2814
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.8.65536.10.2 = Gauge32: 100
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.8.65536.10.3 = Gauge32: 100
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.9.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.9.65536.10.2 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.9.65536.10.3 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.10.65536.10.1 = Gauge32: 30
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.10.65536.10.2 = Gauge32: 33
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.10.65536.10.3 = Gauge32: 24
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.11.65536.10.1 = STRING: "20.0/2.0"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.11.65536.10.2 = STRING: "20.0/2.0"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.11.65536.10.3 = STRING: "20.0/2.0"
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.12.65536.10.1 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.12.65536.10.2 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.12.65536.10.3 = Counter32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.13.65536.10.1 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.13.65536.10.2 = Gauge32: 0
+# .1.3.6.1.4.1.9.9.449.1.4.1.1.13.65536.10.3 = Gauge32: 0
+#
+# sample info
+# [
+#  [
+#   [u'65536.10.0', u'1', u'\n\xa7\xdd7', u'10', u'2', u'01:05:34', u'1', u'100', u'0', u'147', u'23.0/2.0', u'0', u'0']
+#  ],
+#  [
+#   [u'1', u'FastEthernet0', u'6'],
+#   [u'2', u'FastEthernet1', u'6'],
+#   [u'3', u'FastEthernet2', u'6'],
+#   [u'4', u'FastEthernet3', u'6'],
+#   [u'5', u'FastEthernet4', u'6'],
+#   [u'6', u'VoIP-Null0', u'1'],
+#   [u'7', u'Null0', u'1'],
+#   [u'8', u'Vlan1', u'53'],
+#   [u'9', u'Loopback0', u'24'],
+#   [u'10', u'Tunnel100', u'131']
+#  ]
+# ]
+#
+
+import re
+from dataclasses import dataclass
+from typing import List, Dict
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    Result,
+    check_levels,
+    State,
+    SNMPTree,
+    all_of,
+    contains,
+    exists,
+    OIDEnd,
+    Metric,
+    render,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+
+@dataclass
+class EigrpPeer:
+    cEigrpPeerAS: str
+    cEigrpPeerAddr: str
+    cEigrpUpTimeSeconds: int
+    cEigrpSrtt: int
+    cEigrpRto: int
+    cEigrpPktsEnqueued: int
+    cEigrpRetrans: int
+    cEigrpRetries: int
+    cEigrpHoldTime: int
+    cEigrpVrfName: str
+    cEigrpVrfId: int
+    cEigrpAddrFammily: str
+    PeerInterface: str
+
+
+_InetAddressType = {
+    0: 'unknown',
+    1: 'ipv4',
+    2: 'ipv6',
+    3: 'ipv4z',
+    4: 'ipv6z',
+    16: 'dns',
+}
+
+
+def _render_ip4_address(bytestring: str) -> str:
+    if len(bytestring) == 4:  # byte sting length = 4 bytes
+        return ".".join(["%s" % ord(m) for m in bytestring])
+    elif len(bytestring) >= 7:  # ipv4 address > 4 octets + 3 dots
+        return bytestring
+
+
+def _shorten_ipv6_adress(address: str) -> str:
+    address = address.split(':')
+    span = 2
+    address = [''.join(address[i:i + span]) for i in range(0, len(address), span)]
+    for m in range(0, len(address)):
+        address[m] = re.sub(r'^0{1,3}', r'', address[m])
+    address = ':'.join(address)
+    zeros = ':0:0:0:0:0:0:'
+    while not zeros == '':
+        if zeros in address:
+            address = re.sub(r'%s' % zeros, r'::', address)
+            zeros = ''
+        else:
+            zeros = zeros[:-2]
+    if address == '0::0':
+        address = '::'
+
+    return address
+
+
+def _render_ipv6_address(bytestring: str) -> str:
+    address = ":".join(["%02s" % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper()
+    address = _shorten_ipv6_adress(address)
+
+    return address
+
+
+def _get_uptime(uptimestr: str) -> int:
+    uptime_in_sec = 0
+    if 'y' in uptimestr and 'w' in uptimestr:
+        uptimestr = uptimestr.split('y')
+        uptime_in_sec = int(uptimestr[0]) * 31536000  # 365 * 24 * 3600, one year
+        uptime_in_sec += int(uptimestr[1][:-1]) * 604800  # 7 * 24 * 3600, one week
+    if 'w' in uptimestr and 'd' in uptimestr:
+        uptimestr = uptimestr.split('w')
+        uptime_in_sec = int(uptimestr[0]) * 604800  # 7 * 24 * 3600, one week
+        uptime_in_sec += int(uptimestr[1][:-1]) * 86400  # 24 * 3600, on day
+    elif 'd' in uptimestr and 'h' in uptimestr:
+        uptimestr = uptimestr.split('d')
+        uptime_in_sec = int(uptimestr[0]) * 86400  # 24 * 3600, one day
+        uptime_in_sec += int(uptimestr[1][:-1]) * 3600
+    elif ':' in uptimestr:
+        uptime_in_sec = uptimestr.split(':')
+        if len(uptime_in_sec) == 3:  # [19:20:00] hours:minutes:seconds
+            uptime_in_sec = (int(uptime_in_sec[0]) * 3600) + (int(uptime_in_sec[1]) * 60) + int(uptime_in_sec[2])
+        elif len(uptime_in_sec) == 4:  # [10:19:20:00]   days(?):hours:minutes:seconds
+            uptime_in_sec = (int(uptime_in_sec[0]) * 86400) + \
+                            (int(uptime_in_sec[1]) * 3600) + \
+                            (int(uptime_in_sec[2]) * 60) + \
+                            int(uptime_in_sec[3])
+
+    return uptime_in_sec
+
+###########################################################################
+#
+#  DATA Parser function
+#
+###########################################################################
+
+
+def parse_cisco_eigrp_peers(string_table: List[StringTable]) -> Dict[str, EigrpPeer]:
+    peers, peer_interfaces, VrfInfo = string_table
+    PeerTable = {}
+
+    for peer in peers:
+        OID_END, cEigrpPeerAddrType, cEigrpPeerAddr, cEigrpPeerIfIndex, cEigrpHoldTime, cEigrpUpTime, cEigrpSrtt, \
+        cEigrpRto, cEigrpPktsEnqueued, cEigrpRetrans, cEigrpRetries = peer
+
+        cEigrpVrfId = int(OID_END.split('.')[0])
+        cEigrpPeerAS = OID_END.split('.')[1]
+        cEigrpAddrFammily = int(OID_END.split('.')[2])
+        if int(cEigrpPeerAddrType) == 1:  # IPv4 address
+            cEigrpPeerAddr = _render_ip4_address(cEigrpPeerAddr)
+        elif int(cEigrpPeerAddrType) == 2:  # IPv4 address
+            cEigrpPeerAddr = _render_ipv6_address(cEigrpPeerAddr)
+
+        PeerInterface = ''
+        for ifIndex, ifDescr, ifType in peer_interfaces:
+            if int(cEigrpPeerIfIndex) == int(ifIndex):
+                PeerInterface = ifDescr
+
+        cEigrpVrfName = ''
+        for VrfId, VrfName in VrfInfo:
+            if int(VrfId) == cEigrpVrfId:
+                cEigrpVrfName = VrfName
+
+        if cEigrpAddrFammily == 2:
+            cEigrpAddrFammily = 'IPv6'
+        else:
+            cEigrpAddrFammily = 'IPv4'
+
+        if cEigrpVrfName == 'default':
+            ServiceText = f'{cEigrpPeerAddr} on AS {cEigrpPeerAS}'
+        else:
+            ServiceText = f'{cEigrpPeerAddr} on AS {cEigrpPeerAS}, VRF {cEigrpVrfName}'
+
+        PeerTable[ServiceText] = EigrpPeer(
+            cEigrpPeerAS=cEigrpPeerAS,
+            cEigrpPeerAddr=cEigrpPeerAddr,
+            cEigrpUpTimeSeconds=_get_uptime(cEigrpUpTime),
+            cEigrpSrtt=int(cEigrpSrtt),
+            cEigrpRto=int(cEigrpRto),
+            cEigrpPktsEnqueued=int(cEigrpPktsEnqueued),
+            cEigrpRetrans=int(cEigrpRetrans),
+            cEigrpRetries=int(cEigrpRetries),
+            cEigrpHoldTime=int(cEigrpHoldTime),
+            cEigrpVrfName=cEigrpVrfName,
+            cEigrpVrfId=cEigrpVrfId,
+            cEigrpAddrFammily=cEigrpAddrFammily,
+            PeerInterface=PeerInterface,
+        )
+
+    return PeerTable
+
+
+###########################################################################
+#
+#  INVENTORY function
+#
+###########################################################################
+
+
+def discovery_cisco_eigrp_peers(section: Dict[str, EigrpPeer]) -> DiscoveryResult:
+    for key in section:
+        yield Service(item=key)
+
+
+###########################################################################
+#
+#  CHECK function
+#
+###########################################################################
+
+
+def check_cisco_eigrp_peers(item, params, section: Dict[str, EigrpPeer]) -> CheckResult:
+    try:
+        peer = section[item]
+    except KeyError:
+        yield Result(state=State.CRIT, summary='Peer not found in SNMP data')
+        return
+
+    yield from check_levels(
+        label='Uptime',
+        value=peer.cEigrpUpTimeSeconds,
+        metric_name='uptime',
+        render_func=render.timespan,
+        levels_lower=params['minuptime']
+    )
+
+    yield Result(state=State.OK, notice=f'On interface: {peer.PeerInterface}')
+    yield Result(state=State.OK, notice=f'Hold time: {peer.cEigrpHoldTime}')
+
+    for key, value in [
+                ('cEigrpPktsEnqueued', peer.cEigrpPktsEnqueued),
+                ('cEigrpRetrans', peer.cEigrpRetrans),
+                ('cEigrpRetries', peer.cEigrpRetries),
+                ('cEigrpSrtt', peer.cEigrpSrtt),
+                ('cEigrpRto', peer.cEigrpRto),
+            ]:
+        yield Metric(name=f'cisco_eigrp_peers_{key}', value=value)
+
+
+###########################################################################
+#
+#  CHECK info
+#
+###########################################################################
+
+register.snmp_section(
+    name='cisco_eigrp_peers',
+    parse_function=parse_cisco_eigrp_peers,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.4.1.1',  #
+            oids=[
+                OIDEnd(),  # u'65536.10.0'
+                '2',  # cEigrpPeerAddrType
+                '3',  # cEigrpPeerAddr
+                '4',  # cEigrpPeerIfIndex
+                '5',  # cEigrpHoldTime
+                '6',  # cEigrpUpTime
+                '7',  # cEigrpSrtt
+                '8',  # cEigrpRto
+                '9',  # cEigrpPktsEnqueued
+                '12',  # cEigrpRetrans
+                '13',  # cEigrpRetries
+                # '10',     # cEigrpLastSeq
+                # '11',     # cEigrpVersion
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.2.1.2.2.1',  #
+            oids=[
+                '1',  # ifIndex
+                '2',  # ifDescr
+                '3',  # ifType
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.1.1.1',  #
+            oids=[
+                OIDEnd(),  # VRF ID
+                '2',  # cEigrpVpnName
+            ]
+        ),
+    ],
+    detect=all_of(
+        contains('.1.3.6.1.2.1.1.1.0', 'cisco'),  # sysDescr
+        exists('.1.3.6.1.4.1.9.9.449.1.4.1.1.*'),  # CISCO-EIGRP-MIB::cEigrpPeerEntry
+    ))
+
+register.check_plugin(
+    name='cisco_eigrp_peers',
+    service_name='EIGRP peer %s',
+    discovery_function=discovery_cisco_eigrp_peers,
+    check_function=check_cisco_eigrp_peers,
+    check_default_parameters={
+        'minuptime': (3600, 7200)
+    },
+    check_ruleset_name='cisco_eigrp_peers',
+)
diff --git a/agent_based/cisco_eigrp_topology_table.py b/agent_based/cisco_eigrp_topology_table.py
new file mode 100644
index 0000000..7321176
--- /dev/null
+++ b/agent_based/cisco_eigrp_topology_table.py
@@ -0,0 +1,488 @@
+#!/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-17-20
+#
+# Monitor status of Cisco EIGRP Topology Table
+#
+# 2018-02-11: removed unnecessary OIDs
+# 2018-08-06: modified scan function
+# 2019-10-16: added initial IPv6 support, added parser function
+#
+#
+# snmpwalk sample
+#
+# OMD[mysite]:~$ snmpwalk -ObentU -v2c -c router-01 simulant .1.3.6.1.4.1.9.9.449.1.3.1.1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.0.0.0.0.0 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.0.28 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.16.28 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.48.30 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.249.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.254.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.220.255.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.221.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.10.167.222.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.192.168.50.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.5.65536.10.1.4.192.168.55.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.0.0.0.0.0 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.0.28 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.16.28 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.48.30 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.249.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.254.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.220.255.32 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.221.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.10.167.222.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.192.168.50.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.6.65536.10.1.4.192.168.55.0.24 = INTEGER: 2
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.0.0.0.0.0 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.0.28 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.16.28 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.48.30 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.249.32 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.254.32 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.220.255.32 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.221.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.10.167.222.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.192.168.50.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.7.65536.10.1.4.192.168.55.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.0.0.0.0.0 = Gauge32: 28416
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.0.28 = Gauge32: 28416
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.16.28 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.48.30 = Gauge32: 27904
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.249.32 = Gauge32: 1915392
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.254.32 = Gauge32: 128256
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.220.255.32 = Gauge32: 155904
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.221.0.24 = Gauge32: 1787392
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.10.167.222.0.24 = Gauge32: 3523840
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.192.168.50.0.24 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.8.65536.10.1.4.192.168.55.0.24 = Gauge32: 28416
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.0.0.0.0.0 = STRING: "Summary"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.0.28 = STRING: "Internal"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.16.28 = STRING: "Connected"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.48.30 = STRING: "Connected"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.249.32 = STRING: "Internal"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.254.32 = STRING: "Connected"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.220.255.32 = STRING: "Internal"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.221.0.24 = STRING: "Internal"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.10.167.222.0.24 = STRING: "Connected"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.192.168.50.0.24 = STRING: "Rstatic"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.9.65536.10.1.4.192.168.55.0.24 = STRING: "External"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.0.0.0.0.0 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.0.28 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.16.28 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.48.30 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.249.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.254.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.220.255.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.221.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.10.167.222.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.192.168.50.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.10.65536.10.1.4.192.168.55.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.0.0.0.0.0 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.0.28 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.16.28 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.48.30 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.249.32 = Hex-STRING: 0A A7 DE 3A
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.254.32 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.220.255.32 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.221.0.24 = Hex-STRING: 0A A7 DE 3A
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.10.167.222.0.24 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.192.168.50.0.24 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.11.65536.10.1.4.192.168.55.0.24 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.0.0.0.0.0 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.0.28 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.16.28 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.48.30 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.249.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.254.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.220.255.32 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.221.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.10.167.222.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.192.168.50.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.12.65536.10.1.4.192.168.55.0.24 = INTEGER: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.0.0.0.0.0 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.0.28 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.16.28 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.48.30 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.249.32 = Hex-STRING: 0A A7 DE 3A
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.254.32 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.220.255.32 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.221.0.24 = Hex-STRING: 0A A7 DE 3A
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.10.167.222.0.24 = Hex-STRING: 00 00 00 00
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.192.168.50.0.24 = Hex-STRING: 0A A7 DC 11
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.13.65536.10.1.4.192.168.55.0.24 = Hex-STRING: 0A A7 DC 31
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.0.0.0.0.0 = STRING: "Null0"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.0.28 = STRING: "Tunnel10"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.16.28 = STRING: "GigabitEthernet0/0/0"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.48.30 = STRING: "Tunnel10"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.249.32 = STRING: "Tunnel101"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.254.32 = STRING: "Loopback0"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.220.255.32 = STRING: "Tunnel10"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.221.0.24 = STRING: "Tunnel101"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.10.167.222.0.24 = STRING: "Tunnel101"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.192.168.50.0.24 = ""
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.14.65536.10.1.4.192.168.55.0.24 = STRING: "Tunnel10"
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.0.0.0.0.0 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.0.28 = Gauge32: 28416
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.16.28 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.48.30 = Gauge32: 27904
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.249.32 = Gauge32: 3651840
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.254.32 = Gauge32: 128256
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.220.255.32 = Gauge32: 155904
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.221.0.24 = Gauge32: 4035840
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.10.167.222.0.24 = Gauge32: 3523840
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.192.168.50.0.24 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.15.65536.10.1.4.192.168.55.0.24 = Gauge32: 28416
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.0.0.0.0.0 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.0.28 = Gauge32: 2816
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.16.28 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.48.30 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.249.32 = Gauge32: 128256
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.254.32 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.220.255.32 = Gauge32: 128256
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.221.0.24 = Gauge32: 1761792
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.10.167.222.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.192.168.50.0.24 = Gauge32: 1
+# .1.3.6.1.4.1.9.9.449.1.3.1.1.16.65536.10.1.4.192.168.55.0.24 = Gauge32: 2816
+#
+# sample info
+# [
+#  [u'65536.10.1.4.0.0.0.0.0', u'2', u'2', u'External', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd7', u'Tunnel100'],
+#  [u'65536.10.1.4.10.167.220.0.28', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd7', u'Tunnel100'],
+#  [u'65536.10.1.4.10.167.220.249.32', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd:', u'Tunnel100'],
+#  [u'65536.10.1.4.10.167.220.252.32', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd<', u'Tunnel100'],
+#  [u'65536.10.1.4.10.167.220.253.32', u'2', u'2', u'Connected', u'1', u'\x00\x00\x00\x00', u'1', u'\x00\x00\x00\x00', u'Loopback0'],
+#  [u'65536.10.1.4.10.167.220.255.32', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd7', u'Tunnel100'],
+#  [u'65536.10.1.4.10.167.221.0.24', u'2', u'2', u'Connected', u'1', u'\x00\x00\x00\x00', u'1', u'\x00\x00\x00\x00', u'Tunnel100'],
+#  [u'65536.10.1.4.192.168.57.0.24', u'2', u'2', u'Connected', u'1', u'\x00\x00\x00\x00', u'1', u'\x00\x00\x00\x00', u'Vlan1'],
+#  [u'65536.10.1.4.192.168.58.0.24', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd:', u'Tunnel100'],
+#  [u'65536.10.1.4.192.168.60.0.24', u'2', u'2', u'Internal', u'1', u'\n\xa7\xdd7', u'1', u'\n\xa7\xdd<', u'Tunnel100']
+# ]
+#
+
+
+import re
+from dataclasses import dataclass
+from typing import Optional, List
+
+from cmk.base.plugins.agent_based.agent_based_api.v1 import (
+    register,
+    Service,
+    Result,
+    State,
+    SNMPTree,
+    all_of,
+    contains,
+    exists,
+    OIDEnd,
+    Metric,
+)
+from cmk.base.plugins.agent_based.agent_based_api.v1.type_defs import (
+    DiscoveryResult,
+    CheckResult,
+    StringTable,
+)
+
+_InetAddressType = {
+    0: 'unknown',
+    1: 'ipv4',
+    2: 'ipv6',
+    3: 'ipv4z',
+    4: 'ipv6z',
+    16: 'dns',
+}
+
+
+def _render_ip_route(route):  # sample: '65536.10.1.4.192.168.55.0.24'
+    route = route.split('.')
+    if int(route[2]) == 1:  # ipv4 route + masklength
+        route = '.'.join(route[4:8]) + '/' + route[8]
+        #                     1  2 3 4 5 6 7 8 9 0 1 2 3 4 5 6
+    elif int(route[2]) == 2:  # IPv6 131072.10.2.16.48.0.0.0.0.0.0.0.0.3.0.3.0.3.0.32.128
+        for i in range(4, 20, 1):
+            route[i] = '%02s' % hex(int(route[i]))[2:]
+        address = ':'.join(route[4:20]).replace(' ', '0').upper()
+        route = _shorten_ipv6_adress(address) + '/' + route[20]
+    else:
+        route = 'unknown address type'
+    return route  # sample: 192.168.55.0/24
+
+
+def _render_ip4_address(bytestring):
+    if len(bytestring) == 4:  # byte sting length = 4 bytes
+        return '.'.join(['%s' % ord(m) for m in bytestring])
+    elif len(bytestring) >= 7:  # ipv4 address > 4 octets + 3 dots
+        return bytestring
+
+
+def _shorten_ipv6_adress(address):
+    address = address.split(':')
+    span = 2
+    address = [''.join(address[i:i + span]) for i in range(0, len(address), span)]
+    for m in range(0, len(address)):
+        address[m] = re.sub(r'^0{1,3}', r'', address[m])
+    address = ':'.join(address)
+    zeros = ':0:0:0:0:0:0:'
+    while not zeros == '':
+        if zeros in address:
+            address = re.sub(r'%s' % zeros, r'::', address)
+            zeros = ''
+        else:
+            zeros = zeros[:-2]
+    if address == '0::0':
+        address = '::'
+    return address
+
+
+def _render_ipv6_address(bytestring):
+    address = ":".join(["%02s" % hex(ord(m))[2:] for m in bytestring]).replace(' ', '0').upper()
+    address = _shorten_ipv6_adress(address)
+
+    return address
+
+
+###########################################################################
+#
+#  DATA Parser function
+#
+###########################################################################
+
+
+def parse_cisco_eigrp_topology_table(string_table: List[StringTable]):
+    TopologieTable = []
+    ASTable = {}
+    Topologie, VrfInfo = string_table
+
+    # 65536.<AS number>.1.4.<network>.<cidr> --> 65536.10.1.4.10.167.220.0.28
+    for OID_END, cEigrpActive, cEigrpStuckInActive, cEigrpRouteOriginType, cEigrpRouteOriginAddrType, \
+        cEigrpRouteOriginAddr, cEigrpNextHopAddressType, cEigrpNextHopAddress, cEigrpNextHopInterface in Topologie:
+
+        cEigrpVrfId = int(OID_END.split('.')[0])
+        cEigrpAS = OID_END.split('.')[1]
+        cEigrpAddrFammily = int(OID_END.split('.')[2])
+        cEigrpRoute = _render_ip_route(OID_END)
+
+        if int(cEigrpRouteOriginAddrType) == 1:  # IPv4
+            cEigrpRouteOriginAddr = _render_ip4_address(cEigrpRouteOriginAddr)
+        elif int(cEigrpRouteOriginAddrType) == 2:  # IPv6
+            cEigrpRouteOriginAddr = _render_ipv6_address(cEigrpRouteOriginAddr)
+
+        if int(cEigrpNextHopAddressType) == 1:  # IPv4
+            cEigrpNextHopAddress = _render_ip4_address(cEigrpNextHopAddress)
+        if int(cEigrpNextHopAddressType) == 2:  # IPv6
+            cEigrpNextHopAddress = _render_ipv6_address(cEigrpNextHopAddress)
+
+        cEigrpVrfName = ''
+        for VrfId, VrfName in VrfInfo:
+            if int(VrfId) == cEigrpVrfId:
+                cEigrpVrfName = VrfName
+
+        if cEigrpAddrFammily == 2:
+            cEigrpAddrFammily = 'IPv6'
+        else:
+            cEigrpAddrFammily = 'IPv4'
+
+        TopologieTable.append({
+            'cEigrpActive': int(cEigrpActive),
+            'cEigrpStuckInActive': int(cEigrpStuckInActive),
+            'cEigrpRouteOriginType': cEigrpRouteOriginType,
+            'cEigrpRouteOriginAddr': cEigrpRouteOriginAddr,
+            'cEigrpNextHopAddress': cEigrpNextHopAddress,
+            'cEigrpNextHopInterface': cEigrpNextHopInterface,
+            'cEigrpVrfName': cEigrpVrfName,
+            'cEigrpAddrFammily': cEigrpAddrFammily,
+            'cEigrpVrfId': cEigrpVrfId,
+            'cEigrpAS': cEigrpAS,
+            'cEigrpRoute': cEigrpRoute,
+        })
+
+        if cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv4':
+            ASTable.update({cEigrpVrfId: {'ServiceText': cEigrpAS, 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName == 'default' and cEigrpAddrFammily == 'IPv6':
+            ASTable.update({cEigrpVrfId: {'ServiceText': f'{cEigrpAS} IPv6', 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv4':
+            ASTable.update(
+                {cEigrpVrfId: {'ServiceText': f'{cEigrpAS} VRF {cEigrpVrfName}', 'cEigrpVrfId': cEigrpVrfId}})
+        elif cEigrpVrfName != 'default' and cEigrpAddrFammily == 'IPv6':
+            ASTable.update({cEigrpVrfId: {'ServiceText': f'{cEigrpAS} IPv6 VRF {cEigrpVrfName}',
+                                          'cEigrpVrfId': cEigrpVrfId}})
+
+    return [ASTable, TopologieTable]
+
+
+###########################################################################
+#
+#  INVENTORY function
+#
+###########################################################################
+
+
+def discovery_cisco_eigrp_topology_table(section) -> DiscoveryResult:
+    ASTable, TopologieTable = section
+    ASTable = dict(ASTable)
+    for Key in ASTable.keys():
+        ServiceText = ASTable.get(Key).get('ServiceText')
+        yield Service(item=ServiceText)
+
+
+###########################################################################
+#
+#  CHECK function
+#
+###########################################################################
+
+
+def check_cisco_eigrp_topology_table(item, params, section) -> CheckResult:
+    ASTable, TopologieTable = section
+    ASTable = dict(ASTable)
+    cEigrpVrfId = ''
+    for Key in ASTable.keys():
+        ServiceText = ASTable.get(Key).get('ServiceText')
+        if ServiceText == item:
+            cEigrpVrfId = ASTable.get(Key).get('cEigrpVrfId')
+
+    if cEigrpVrfId != '':
+        routes = []
+        activeroutes = []
+        siaroutes = []
+        origintypes = {
+            'Static_redistributed': 0,
+            'Internal': 0,
+            'Connected': 0,
+            'External': 0,
+            'Summary': 0,
+            'InetAddress': 0,
+        }
+
+        for route in TopologieTable:
+            if route.get('cEigrpVrfId') == cEigrpVrfId:
+                cEigrpActive = route.get('cEigrpActive')
+                cEigrpStuckInActive = route.get('cEigrpStuckInActive')
+                cEigrpRouteOriginType = route.get('cEigrpRouteOriginType')
+
+                # count routes
+                routes.append(route)
+
+                # count active routes
+                if cEigrpActive == 1:
+                    activeroutes.append(route)
+
+                # count sia routes
+                if cEigrpStuckInActive == 1:
+                    siaroutes.append(route)
+
+                # count origin types (Rstatic, Internal, Connected, External, Summary, and so on...)
+                if cEigrpRouteOriginType == 'Rstatic':
+                    cEigrpRouteOriginType = 'Static_redistributed'
+                origintype = 0
+                if origintypes.get(cEigrpRouteOriginType):
+                    origintype = origintypes.get(cEigrpRouteOriginType)
+                origintype += 1
+                origintypes.update({cEigrpRouteOriginType: origintype})
+
+        if not len(routes) == 0:
+            yield Result(state=State.OK, summary=f'Routes in topology table: {len(routes)}')
+
+        if not len(activeroutes) == 0:
+            if 'activeroutes' not in params.get('nowarnon'):
+                yield Result(state=State.WARN, notice='Active route found')
+            for route in activeroutes:
+                cEigrpRoute = route.get('cEigrpRoute')
+                cEigrpRouteOriginAddr = route.get('cEigrpRouteOriginAddr')
+                cEigrpNextHopAddress = route.get('cEigrpNextHopAddress')
+                cEigrpNextHopInterface = route.get('cEigrpNextHopInterface')
+
+                yield Result(
+                    state=State.OK,
+                    notice=f'Active Route: {cEigrpRoute}, '
+                           f'originated by {cEigrpRouteOriginAddr} '
+                           f'on interface: {cEigrpNextHopInterface}, '
+                           f'next hop: {cEigrpNextHopAddress}'
+                )
+
+        if not len(siaroutes) == 0:
+            if 'siaroutes' not in params.get('nowarnon'):
+                yield Result(state=State.WARN, notice='Stuck in active (SIA) route found')
+
+            for route in siaroutes:
+                cEigrpRoute = route.get('cEigrpRoute')
+                cEigrpRouteOriginAddr = route.get('cEigrpRouteOriginAddr')
+                cEigrpNextHopAddress = route.get('cEigrpNextHopAddress')
+                cEigrpNextHopInterface = route.get('cEigrpNextHopInterface')
+
+                yield Result(
+                    state=State.OK,
+                    notice=f'SIA Route: {cEigrpRoute}, '
+                           f'originated by {cEigrpRouteOriginAddr} '
+                           f'on interface: {cEigrpNextHopInterface}, '
+                           f'next hop: {cEigrpNextHopAddress}'
+                )
+
+        for key, value in [
+            ('activeroutes', len(activeroutes)),
+            ('siaroutes', len(siaroutes)),
+            ('routes', len(routes)),
+        ]:
+            yield Metric(name=f'cisco_eigrp_topology_table_{key}', value=value)
+
+        # append perfdata for routes by origin type
+        for origintype in origintypes:
+            yield Metric(name=f'cisco_eigrp_topology_table_{origintype}', value=origintypes.get(origintype))
+
+
+###########################################################################
+#
+#  CHECK info
+#
+###########################################################################
+
+
+register.snmp_section(
+    name='cisco_eigrp_topology_table',
+    parse_function=parse_cisco_eigrp_topology_table,
+    fetch=[
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.3.1.1',  #
+            oids=[
+                OIDEnd(),  # 65536.<AS number>.1.4.<network>.<cidr> --> 65536.10.1.4.10.167.220.0.28
+                '5',  # cEigrpActive              [1]
+                '6',  # cEigrpStuckInActive       [2]
+                '9',  # cEigrpRouteOriginType     [3]
+                '10',  # cEigrpRouteOriginAddrType [4]
+                '11',  # cEigrpRouteOriginAddr     [5]
+                '12',  # cEigrpNextHopAddressType  [6]
+                '13',  # cEigrpNextHopAddress      [7]
+                '14',  # cEigrpNextHopInterface    [8]
+                # '7',     # cEigrpDestSuccessors    []
+                # '8',     # cEigrpFdistance         []
+                # '16',    # cEigrpReportDistance    []
+                # '15',    # cEigrpDistance          []
+            ]
+        ),
+        SNMPTree(
+            base='.1.3.6.1.4.1.9.9.449.1.1.1.1',  #
+            oids=[
+                OIDEnd(),  # VRF ID
+                '2',  # cEigrpVpnName [0]
+            ]
+        )
+    ],
+    detect=all_of(
+        contains('.1.3.6.1.2.1.1.1.0', 'cisco'),  # sysDescr
+        exists('.1.3.6.1.4.1.9.9.449.1.3.1.1.*'),  # CISCO-EIGRP-MIB::cEigrpTopoEntry
+    ))
+
+register.check_plugin(
+    name='cisco_eigrp_topology_table',
+    service_name='EIGRP topology table AS %s',
+    discovery_function=discovery_cisco_eigrp_topology_table,
+    check_function=check_cisco_eigrp_topology_table,
+    check_default_parameters={
+        'nowarnon': []},
+    check_ruleset_name='cisco_eigrp_topology_table',
+)
diff --git a/cisco_eigrp.mkp b/cisco_eigrp.mkp
index 659dae5c9257e331f6d973a414774dfae0955734..dfcb2748b97ed2902a71a4be6a6fca09644671a3 100644
GIT binary patch
literal 14416
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
PK=4rP+B%S3P>}xuH5exj

literal 15338
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
W;Q#)QV3qfSNHEf>53~ym^nU;XsM*;7

diff --git a/packages/cisco_eigrp b/packages/cisco_eigrp
index 627b2d4..76361d4 100644
--- a/packages/cisco_eigrp
+++ b/packages/cisco_eigrp
@@ -1,17 +1,26 @@
-{'author': u'Th.L. (thl-cmk[at]outlook[dot]com)',
- 'description': u'Monitor Cisco EIGRP. Checks:\n - cisco_eigrp_peers: creates one service for the every IPv4/IPV6 peer, AS and VRF\n - cisco_eigrp_as_info: creates one service per autonomous system (AS)\n - cisco_eigrp_interface: creates one service per EIGRP enabled interface and AS\n - cisco_eigrp_topology_table: creates one service per topology table, AS and VRF\n',
+{'author': 'Th.L. (thl-cmk[at]outlook[dot]com)',
+ 'description': 'Monitor Cisco EIGRP. Checks:\n'
+                ' - cisco_eigrp_peers: creates one service for the every '
+                'IPv4/IPV6 peer, AS and VRF\n'
+                ' - cisco_eigrp_as_info: creates one service per autonomous '
+                'system (AS)\n'
+                ' - cisco_eigrp_interface: creates one service per EIGRP '
+                'enabled interface and AS\n'
+                ' - cisco_eigrp_topology_table: creates one service per '
+                'topology table, AS and VRF\n',
  'download_url': 'https://thl-cmk.hopto.org',
- 'files': {'checks': ['cisco_eigrp_peers',
-                      'cisco_eigrp_as_info',
-                      'cisco_eigrp_interface',
-                      'cisco_eigrp_topology_table'],
+ 'files': {'agent_based': ['cisco_eigrp_as_info.py',
+                           'cisco_eigrp_interface.py',
+                           'cisco_eigrp_peers.py',
+                           'cisco_eigrp_topology_table.py'],
            'web': ['plugins/wato/cisco_eigrp_peers.py',
                    'plugins/wato/cisco_eigrp_interface.py',
                    'plugins/wato/cisco_eigrp_topology_table.py',
                    'plugins/metrics/cisco_eigrp.py']},
  'name': 'cisco_eigrp',
  'num_files': 8,
- 'title': u'Cisco EIGRP checks',
- 'version': '20191021v.0.2a',
- 'version.min_required': '1.2.8b8',
- 'version.packaged': '1.4.0p35'}
\ No newline at end of file
+ 'title': 'Cisco EIGRP checks',
+ 'version': '20210803v.0.3',
+ 'version.min_required': '2.0.0',
+ 'version.packaged': '2021.07.14',
+ 'version.usable_until': None}
\ No newline at end of file
diff --git a/web/plugins/metrics/cisco_eigrp.py b/web/plugins/metrics/cisco_eigrp.py
index a572e40..f2b52d0 100644
--- a/web/plugins/metrics/cisco_eigrp.py
+++ b/web/plugins/metrics/cisco_eigrp.py
@@ -1,49 +1,25 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
 #
-# Cisco EIGRP Peer metrics plugin
+# License: GNU General Public License v2
 #
-# Author: Th.L.
+# Author: thl-cmk[at]outlook[dot]com
+# URL   : https://thl-cmk.hopto.org
 # Date  : 2017-12-26
 #
-# replaces :
-#           local/share/check_mk/pnp-templates/check_mk-cisco_eigrp_peers.php
-#           local/share/check_mk/web/plugins/perfometer/cisco_eigrp_peers.py
+# Cisco EIGRP Peer metrics plugin
 #
 # missing a way to include hostname and service description
 #
 
-# key a       green      11/a       21/a       31/a       41/a       12/a       22/a       32/a       42/a
-colors_a = ['#80F000', '#a500ff', '#ffc600', '#00ffb2', '#0075ff', '#cc00ff', '#ffd600', '#00ffff', '#0047ff',
-            # 13/a       23/a       33/a       43/a       14/a       24/a       34/a       44/a       15/a
-            '#f900ff', '#ffed00', '#00e8ff', '#000aff', '#ff4c00', '#e2ff00', '#00d1ff', '#4200ff', '#ff7a00',
-            # 25/a       35/a       45/a       16/a       26/a       36/a       46/a       51/a       52/a
-            '#bcff00', '#00b2ff', '#6000ff', '#ffa000', '#7fff00', '#0093ff', '#7f00ff', '#7f7f7f', '#7f4a26',
-            # 53/a
-            '#8c531c']
-# key b       green      11/b       21/b       31/b       41/b       12/b       22/b       32/b       42/b
-colors_b = ['#80F000', '#c966ff', '#cc9f00', '#00cc8e', '#66acff', '#e066ff', '#ccab00', '#00cccc', '#6690ff',
-            # 13/b       23/b       33/b       43/b       14/b       24/b       34/b       44/b       15/b
-            '#fb66ff', '#ccbd00', '#00b9cc', '#666cff', '#ff9366', '#b5cc00', '#00a7cc', '#8d66ff', '#ffaf66',
-            # 25/b       35/b       45/b       16/b       26/b       36/b       46/b       51/b       52/b
-            '#96cc00', '#008ecc', '#a066ff', '#ffc666', '#66cc00', '#0076cc', '#b266ff', '#7f7f7f', '#7f5f49',
-            # 53/b
-            '#8c6a48']
-
-
-# def eigrp_render_uptime(uptime):  # expects time in seconds
-#     m, s = divmod(uptime, 60)   # break in seconds / minutes
-#     h, m = divmod(m, 60)        # break in mintes / hours
-#     if h >= 24:                 # more then one day
-#         d, h = divmod(h, 24)    # break in hours / days
-#     else:
-#         return '%02d:%02d:%02d' % (h, m, s)
-#     if d >= 365:                # more the one year
-#         y, d = divmod(d, 365)   # break in days / years
-#         return '%dy %dd %02d:%02d:%02d' % (y, d, h, m, s)
-#     else:
-#         return '%dd %02d:%02d:%02d' % (d, h, m, s)
+from cmk.gui.i18n import _
 
+from cmk.gui.plugins.metrics import (
+    metric_info,
+    graph_info,
+    perfometer_info,
+    unit_info,
+)
 
 #####################################################################################################################
 #
@@ -52,12 +28,6 @@ colors_b = ['#80F000', '#c966ff', '#cc9f00', '#00cc8e', '#66acff', '#e066ff', '#
 #####################################################################################################################
 
 
-# unit_info['uptime'] = {
-#     'title': _('Uptime'),
-#     'description': _('Timespan or Duration in seconds'),
-#     'symbol': _('s'),
-#     'render': lambda v: eigrp_render_uptime(v),
-# }
 unit_info['milliseconds'] = {
     'title': _('Milliseconds'),
     'symbol': 'ms',
@@ -65,72 +35,6 @@ unit_info['milliseconds'] = {
     'stepping': 'integer',  # for vertical graph labels
 }
 
-
-######################################################################################################################
-#
-# map eigrp perfdata to metric, not really necessary but makes sure to use the right metrics
-#
-######################################################################################################################
-
-
-check_metrics['check_mk-cisco_eigrp_peers'] = {
-    'cEigrpUpTime'      : {'name': 'cisco_eigrp_peers_cEigrpUpTime', },
-    'cEigrpRetrans'     : {'name': 'cisco_eigrp_peers_cEigrpRetrans', },
-    'cEigrpRetries'     : {'name': 'cisco_eigrp_peers_cEigrpRetries', },
-    'cEigrpSrtt'        : {'name': 'cisco_eigrp_peers_cEigrpSrtt', },
-    'cEigrpRto'         : {'name': 'cisco_eigrp_peers_cEigrpRto', },
-    'cEigrpPktsEnqueued': {'name': 'cisco_eigrp_peers_cEigrpPktsEnqueued'}
-}
-
-check_metrics['check_mk-cisco_eigrp_interface'] = {
-    'cEigrpPeerCount'      : {'name': 'cisco_eigrp_interface_cEigrpPeerCount', },
-    'cEigrpXmitReliableQ'  : {'name': 'cisco_eigrp_interface_cEigrpXmitReliableQ', },
-    'cEigrpXmitUnreliableQ': {'name': 'cisco_eigrp_interface_cEigrpXmitUnreliableQ', },
-    'cEigrpMeanSrtt'       : {'name': 'cisco_eigrp_interface_cEigrpMeanSrtt', },
-    'cEigrpPendingRoutes'  : {'name': 'cisco_eigrp_interface_cEigrpPendingRoutes', },
-    'cEigrpRMcasts'        : {'name': 'cisco_eigrp_interface_cEigrpRMcasts', },
-    'cEigrpUMcasts'        : {'name': 'cisco_eigrp_interface_cEigrpUMcasts', },
-    'cEigrpUUcasts'        : {'name': 'cisco_eigrp_interface_cEigrpUUcasts', },
-    'cEigrpRUcasts'        : {'name': 'cisco_eigrp_interface_cEigrpRUcasts', },
-    'cEigrpMcastExcepts'   : {'name': 'cisco_eigrp_interface_cEigrpMcastExcepts', },
-    'cEigrpCRpkts'         : {'name': 'cisco_eigrp_interface_cEigrpCRpkts', },
-    'cEigrpAcksSuppressed' : {'name': 'cisco_eigrp_interface_cEigrpAcksSuppressed', },
-    'cEigrpRetransSent'    : {'name': 'cisco_eigrp_interface_cEigrpRetransSent', },
-    'cEigrpOOSrvcd'        : {'name': 'cisco_eigrp_interface_cEigrpOOSrvcd', },
-}
-
-check_metrics['check_mk-cisco_eigrp_topology_table'] = {
-    'Internal'            : {'name': 'cisco_eigrp_topology_table_Internal', },
-    'Connected'           : {'name': 'cisco_eigrp_topology_table_Connected', },
-    'External'            : {'name': 'cisco_eigrp_topology_table_External', },
-    'Summary'             : {'name': 'cisco_eigrp_topology_table_Summary', },
-    'Static_redistributed': {'name': 'cisco_eigrp_topology_table_Static_redistributed', },
-    'InetAddress'         : {'name': 'cisco_eigrp_topology_table_Inetaddress', },
-    'activeroutes'        : {'name': 'cisco_eigrp_topology_table_activeroutes', },
-    'siaroutes'           : {'name': 'cisco_eigrp_topology_table_siaroutes', },
-    'routes'              : {'name': 'cisco_eigrp_topology_table_routes', },
-}
-
-check_metrics['check_mk-cisco_eigrp_as_info'] = {
-    'cEigrpNbrCount'       : {'name': 'cisco_eigrp_as_info_cEigrpNbrCount', },
-    'cEigrpHellosSent'     : {'name': 'cisco_eigrp_as_info_cEigrpHellosSent', },
-    'cEigrpHellosRcvd'     : {'name': 'cisco_eigrp_as_info_cEigrpHellosRcvd', },
-    'cEigrpUpdatesSent'    : {'name': 'cisco_eigrp_as_info_cEigrpUpdatesSent', },
-    'cEigrpUpdatesRcvd'    : {'name': 'cisco_eigrp_as_info_cEigrpUpdatesRcvd', },
-    'cEigrpQueriesSent'    : {'name': 'cisco_eigrp_as_info_cEigrpQueriesSent', },
-    'cEigrpQueriesRcvd'    : {'name': 'cisco_eigrp_as_info_cEigrpQueriesRcvd', },
-    'cEigrpRepliesSent'    : {'name': 'cisco_eigrp_as_info_cEigrpRepliesSent', },
-    'cEigrpRepliesRcvd'    : {'name': 'cisco_eigrp_as_info_cEigrpRepliesRcvd', },
-    'cEigrpAcksSent'       : {'name': 'cisco_eigrp_as_info_cEigrpAcksSent', },
-    'cEigrpAcksRcvd'       : {'name': 'cisco_eigrp_as_info_cEigrpAcksRcvd', },
-    'cEigrpInputQHighMark' : {'name': 'cisco_eigrp_as_info_cEigrpInputQHighMark', },
-    'cEigrpInputQDrops'    : {'name': 'cisco_eigrp_as_info_cEigrpInputQDrops', },
-    'cEigrpSiaQueriesSent' : {'name': 'cisco_eigrp_as_info_cEigrpSiaQueriesSent', },
-    'cEigrpSiaQueriesRcvd' : {'name': 'cisco_eigrp_as_info_cEigrpSiaQueriesRcvd', },
-    'cEigrpTopoRoutes'     : {'name': 'cisco_eigrp_as_info_cEigrpTopoRoutes', },
-    'cEigrpXmitPendReplies': {'name': 'cisco_eigrp_as_info_cEigrpXmitPendReplies', },
-}
-
 #####################################################################################################################
 #
 # define metrics for eigrp peer perfdata
@@ -140,34 +44,34 @@ check_metrics['check_mk-cisco_eigrp_as_info'] = {
 # define metrics for cisco_eigrp_peer perfdata
 
 metric_info['cisco_eigrp_peers_cEigrpUpTime'] = {
-    'title' : _('Peer uptime'),
-    'unit'  : 's',
-    'color' : colors_a[0],
+    'title': _('Peer uptime'),
+    'unit': 's',
+    'color': '26/a',
 }
 metric_info['cisco_eigrp_peers_cEigrpPktsEnqueued'] = {
-    'title' : _('Packets enqueued'),
-    'unit'  : 'count',
-    'color' : colors_a[1],
+    'title': _('Packets enqueued'),
+    'unit': 'count',
+    'color': '11/a',
 }
 metric_info['cisco_eigrp_peers_cEigrpRetrans'] = {
-    'title' : _('Retransmissions'),
-    'unit'  : 'count',
-    'color' : colors_a[2],
+    'title': _('Retransmissions'),
+    'unit': 'count',
+    'color': '21/a',
 }
 metric_info['cisco_eigrp_peers_cEigrpRetries'] = {
-    'title' : _('Retries'),
-    'unit'  : 'count',
-    'color' : colors_a[3],
+    'title': _('Retries'),
+    'unit': 'count',
+    'color': '31/a',
 }
 metric_info['cisco_eigrp_peers_cEigrpSrtt'] = {
     'title': _('Smooth round trip time'),
-    'unit' : 'milliseconds',
-    'color': colors_a[4],
+    'unit': 'milliseconds',
+    'color': '41/a',
 }
 metric_info['cisco_eigrp_peers_cEigrpRto'] = {
-    'title' : _('Retransmission timeout'),
-    'unit'  : 'milliseconds',
-    'color' : colors_b[5],
+    'title': _('Retransmission timeout'),
+    'unit': 'milliseconds',
+    'color': '12/a',
 }
 
 # define metrics for cisco_eigrp_interface perfdata
@@ -175,72 +79,72 @@ metric_info['cisco_eigrp_peers_cEigrpRto'] = {
 metric_info['cisco_eigrp_interface_cEigrpPeerCount'] = {
     'title': _('Peer count'),
     'unit': 'count',
-    'color': colors_a[0],
+    'color': '26/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpXmitReliableQ'] = {
     'title': _('Reliable queue length'),
     'unit': 'count',
-    'color': colors_a[1],
+    'color': '11/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpXmitUnreliableQ'] = {
     'title': _('Unreliable queue length'),
     'unit': 'count',
-    'color': colors_a[2],
+    'color': '21/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpMeanSrtt'] = {
     'title': _('Average smooth round trip time'),
     'unit': 'milliseconds',
-    'color': colors_a[3],
+    'color': '31/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpPendingRoutes'] = {
     'title': _('Routing updates awaiting transmission'),
     'unit': 'count',
-    'color': colors_a[4],
+    'color': '41/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpRMcasts'] = {
     'title': _('Reliable multicasts send'),
     'unit': 'count',
-    'color': colors_a[5],
+    'color': '12/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpUMcasts'] = {
     'title': _('Unreliable multicasts send'),
     'unit': 'count',
-    'color': colors_a[6],
+    'color': '22/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpUUcasts'] = {
     'title': _('Unreliable unicasts send'),
     'unit': 'count',
-    'color': colors_a[7],
+    'color': '32/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpRUcasts'] = {
     'title': _('Reliable unicasts send'),
     'unit': 'count',
-    'color': colors_a[8],
+    'color': '42/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpMcastExcepts'] = {
     'title': _('Multicast exceptions received'),
     'unit': 'count',
-    'color': colors_a[9],
+    'color': '25/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpCRpkts'] = {
     'title': _('Conditional-Receive packets'),
     'unit': 'count',
-    'color': colors_a[10],
+    'color': '35/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpAcksSuppressed'] = {
     'title': _('Suppressed acknowledgements'),
     'unit': 'count',
-    'color': colors_a[11],
+    'color': '45/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpRetransSent'] = {
     'title': _('Retransmissions send'),
     'unit': 'count',
-    'color': colors_a[12],
+    'color': '16/a',
 }
 metric_info['cisco_eigrp_interface_cEigrpOOSrvcd'] = {
     'title': _('Out-of-sequence packets received'),
     'unit': 'count',
-    'color': colors_a[13],
+    'color': '26/b',
 }
 
 # define metrics for cisco_eigrp_topology_table perfdata
@@ -248,47 +152,47 @@ metric_info['cisco_eigrp_interface_cEigrpOOSrvcd'] = {
 metric_info['cisco_eigrp_topology_table_routes'] = {
     'title': _('All routes'),
     'unit': 'count',
-    'color': colors_a[0],
+    'color': '26/a',
 }
 metric_info['cisco_eigrp_topology_table_activeroutes'] = {
     'title': _('Active routes'),
     'unit': 'count',
-    'color': colors_a[1],
+    'color': '11/a',
 }
 metric_info['cisco_eigrp_topology_table_siaroutes'] = {
     'title': _('Stuck in active (SIA) routes'),
     'unit': 'count',
-    'color': colors_a[2],
+    'color': '21/a',
 }
 metric_info['cisco_eigrp_topology_table_Connected'] = {
     'title': _('Connected'),
     'unit': 'count',
-    'color': colors_a[3],
+    'color': '31/a',
 }
 metric_info['cisco_eigrp_topology_table_Internal'] = {
-    'title' : _('Internal'),
-    'unit'  : 'count',
-    'color' : colors_a[4],
+    'title': _('Internal'),
+    'unit': 'count',
+    'color': '41/a',
 }
 metric_info['cisco_eigrp_topology_table_External'] = {
     'title': _('External'),
     'unit': 'count',
-    'color': colors_a[5],
+    'color': '12/a',
 }
 metric_info['cisco_eigrp_topology_table_Summary'] = {
     'title': _('Summary'),
     'unit': 'count',
-    'color': colors_a[6],
+    'color': '22/a',
 }
 metric_info['cisco_eigrp_topology_table_Static_redistributed'] = {
-    'title' : _('Static redistributed'),
-    'unit'  : 'count',
-    'color' : colors_a[14],
+    'title': _('Static redistributed'),
+    'unit': 'count',
+    'color': '24/a',
 }
 metric_info['cisco_eigrp_topology_table_Inetaddress'] = {
     'title': _('Inet address'),
     'unit': 'count',
-    'color': colors_a[17],
+    'color': '15/a',
 }
 
 # define metrics for cisco_eigrp_as_info perfdata
@@ -296,87 +200,87 @@ metric_info['cisco_eigrp_topology_table_Inetaddress'] = {
 metric_info['cisco_eigrp_as_info_cEigrpNbrCount'] = {
     'title': _('Neighbour count'),
     'unit': 'count',
-    'color': colors_a[0],
+    'color': '26/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpHellosSent'] = {
     'title': _('Hellos send'),
     'unit': '1/s',
-    'color': colors_a[1],
+    'color': '11/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpHellosRcvd'] = {
     'title': _('Hellos received'),
     'unit': '1/s',
-    'color': colors_a[2],
+    'color': '21/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpUpdatesSent'] = {
     'title': _('Updates send'),
     'unit': 'count',
-    'color': colors_a[3],
+    'color': '31/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpUpdatesRcvd'] = {
     'title': _('Updates received'),
     'unit': 'count',
-    'color': colors_a[4],
+    'color': '41/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpQueriesSent'] = {
     'title': _('Alternate route queries send'),
     'unit': 'count',
-    'color': colors_a[5],
+    'color': '12/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpQueriesRcvd'] = {
     'title': _('Alternate route queries received'),
     'unit': 'count',
-    'color': colors_a[6],
+    'color': '22/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpRepliesSent'] = {
     'title': _('Reply packets send'),
     'unit': 'count',
-    'color': colors_a[7],
+    'color': '32/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpRepliesRcvd'] = {
     'title': _('Reply packets received'),
     'unit': 'count',
-    'color': colors_a[8],
+    'color': '42/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpAcksSent'] = {
     'title': _('Acknowledgements send'),
     'unit': 'count',
-    'color': colors_a[9],
+    'color': '13/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpAcksRcvd'] = {
     'title': _('Acknowledgements received'),
     'unit': 'count',
-    'color': colors_a[10],
+    'color': '23/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpInputQHighMark'] = {
     'title': _('Highest number of packets in the input queue'),
     'unit': 'count',
-    'color': colors_a[11],
+    'color': '33/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpInputQDrops'] = {
     'title': _('Packets dropped from the input queue'),
     'unit': 'count',
-    'color': colors_a[12],
+    'color': '43/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpSiaQueriesSent'] = {
     'title': _('Stuck in active (SIA) queries sent'),
     'unit': 'count',
-    'color': colors_a[13],
+    'color': '14/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpSiaQueriesRcvd'] = {
     'title': _('Stuck in active (SIA) queries received'),
     'unit': 'count',
-    'color': colors_a[14],
+    'color': '24/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpTopoRoutes'] = {
     'title': _('Routes in the topology table'),
     'unit': 'count',
-    'color': colors_a[15],
+    'color': '34/a',
 }
 metric_info['cisco_eigrp_as_info_cEigrpXmitPendReplies'] = {
     'title': _('Outstanding replies expected to queries send'),
     'unit': 'count',
-    'color': colors_a[16],
+    'color': '44/a',
 }
 
 ######################################################################################################################
@@ -387,55 +291,60 @@ metric_info['cisco_eigrp_as_info_cEigrpXmitPendReplies'] = {
 
 # graphs for cisco_eigrp_peer
 
-graph_info.append({
+graph_info['cisco_eigrp_peer_uptime'] = {
     'title': _('Uptime'),
     'metrics': [
         ('cisco_eigrp_peers_cEigrpUpTime', 'area'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_peer_enqued'] = {
     'title': _('Packets enqueued'),
     'metrics': [
         ('cisco_eigrp_peers_cEigrpPktsEnqueued', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_peer_retransmission'] = {
     'title': _('Smooth round trip time / retransmission timeout'),
     'metrics': [
         ('cisco_eigrp_peers_cEigrpSrtt', 'line'),
         ('cisco_eigrp_peers_cEigrpRto', 'line'),
     ],
-})
-graph_info.append({
+}
+graph_info['cisco_eigrp_peer_error'] = {
     'title': _('Retransmissions / Retries'),
     'metrics': [
         ('cisco_eigrp_peers_cEigrpRetrans', 'line'),
         ('cisco_eigrp_peers_cEigrpRetries', 'line'),
     ],
-})
+}
 
 # graphs for cisco_eigrp_as_info
 
-graph_info.append({
+graph_info['cisco_eigrp_as_info_neighbour_count'] = {
     'title': _('Neighbour count'),
     'metrics': [
         ('cisco_eigrp_as_info_cEigrpNbrCount', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_as_info_route_count'] = {
     'title': _('Routes in the topology table'),
     'metrics': [
         ('cisco_eigrp_as_info_cEigrpTopoRoutes', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_as_info_hellos'] = {
     'title': _('Hellos send/received'),
     'metrics': [
         ('cisco_eigrp_as_info_cEigrpHellosSent', 'line'),
         ('cisco_eigrp_as_info_cEigrpHellosRcvd', '-line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_as_info_packets'] = {
     'title': _('Packets send/received'),
     'metrics': [
         ('cisco_eigrp_as_info_cEigrpQueriesSent', 'line'),
@@ -449,51 +358,57 @@ graph_info.append({
         ('cisco_eigrp_as_info_cEigrpAcksRcvd', '-line'),
         ('cisco_eigrp_as_info_cEigrpSiaQueriesRcvd', '-line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_as_info_drops'] = {
     'title': _('Input queue drops / Queue hi mark'),
     'metrics': [
         ('cisco_eigrp_as_info_cEigrpInputQDrops', 'line'),
         ('cisco_eigrp_as_info_cEigrpInputQHighMark', 'line'),
     ],
-})
+}
 
 # graphs for cisco_eigrp_interface
 
-graph_info.append({
+graph_info['cisco_eigrp_interface_peer_count'] = {
     'title': _('Peer count'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpPeerCount', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_queue_length'] = {
     'title': _('Queue length'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpXmitReliableQ', 'line'),
         ('cisco_eigrp_interface_cEigrpXmitUnreliableQ', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_multicasts'] = {
     'title': _('Multicasts send'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpRMcasts', 'line'),
         ('cisco_eigrp_interface_cEigrpUMcasts', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_unicasts'] = {
     'title': _('Unicasts send'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpUUcasts', 'line'),
         ('cisco_eigrp_interface_cEigrpRUcasts', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_pendinf_routes'] = {
     'title': _('Pending Routes'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpPendingRoutes', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_packets'] = {
     'title': _('Various packets'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpMcastExcepts', 'line'),
@@ -501,23 +416,25 @@ graph_info.append({
         ('cisco_eigrp_interface_cEigrpRetransSent', 'line'),
         ('cisco_eigrp_interface_cEigrpOOSrvcd', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_rtt'] = {
     'title': _('Average smooth round trip time'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpMeanSrtt', 'line'),
     ],
-})
-graph_info.append({
+}
+
+graph_info['cisco_eigrp_interface_ack_suppressed'] = {
     'title': _('Suppressed acknowledgements'),
     'metrics': [
         ('cisco_eigrp_interface_cEigrpAcksSuppressed', 'line'),
     ],
-})
+}
 
 # define metrics for cisco_eigrp_topology_table perfdata
 
-graph_info.append({
+graph_info['cisco_eigrp_topology_table_routes'] = {
     'title': _('Routes by origin type'),
     'metrics': [
         ('cisco_eigrp_topology_table_Inetaddress', 'line'),
@@ -528,17 +445,24 @@ graph_info.append({
         ('cisco_eigrp_topology_table_Connected', 'line'),
         ('cisco_eigrp_topology_table_routes', 'line'),
     ],
+    'optional_metrics': [
+        'cisco_eigrp_topology_table_Inetaddress',
+        'cisco_eigrp_topology_table_Static_redistributed',
+        'cisco_eigrp_topology_table_Summary',
+        'cisco_eigrp_topology_table_External',
+        'cisco_eigrp_topology_table_Internal',
+        'cisco_eigrp_topology_table_Connected',
+    ]
     # 'range': (0, 'cisco_eigrp_topology_table_routes:max')
-})
+}
 
-graph_info.append({
+graph_info['cisco_eigrp_topology_table_active_sia'] = {
     'title': _('Stuck in active (SIA) / active routes'),
     'metrics': [
         ('cisco_eigrp_topology_table_siaroutes', 'line'),
         ('cisco_eigrp_topology_table_activeroutes', 'line'),
     ],
-})
-
+}
 
 ######################################################################################################################
 #
@@ -556,17 +480,17 @@ perfometer_info.append({
 
 # cisco_eigrp_interface send packets
 perfometer_info.append({
-        'type': 'linear',
-        'segments': ['cisco_eigrp_interface_cEigrpPeerCount'],
-        'total': 50,
-    })
+    'type': 'linear',
+    'segments': ['cisco_eigrp_interface_cEigrpPeerCount'],
+    'total': 50,
+})
 
 # cisco_eigrp_topology_table
 perfometer_info.append({
-        'type': 'linear',
-        'segments': ['cisco_eigrp_topology_table_routes'],
-        'total': 1000,
-    })
+    'type': 'linear',
+    'segments': ['cisco_eigrp_topology_table_routes'],
+    'total': 1000,
+})
 
 # cisco_eigrp_as_info
 perfometer_info.append({
diff --git a/web/plugins/wato/cisco_eigrp_interface.py b/web/plugins/wato/cisco_eigrp_interface.py
index 00f8e0b..b15a414 100644
--- a/web/plugins/wato/cisco_eigrp_interface.py
+++ b/web/plugins/wato/cisco_eigrp_interface.py
@@ -1,17 +1,31 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
+#!/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-27
 #
 # Check_MK cisco_eigrp_peer WATO plugin
 #
-# Author: Th.L.
-# Date: 2017-12-27
-#
-#
-#
-#
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    Integer,
+    TextAscii,
+    Tuple,
+    MonitoringState,
+    ListChoice,
+)
 
-ignore_interfaces_auth = [
+from cmk.gui.plugins.wato import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+)
+
+_ignore_interfaces_auth = [
     (6, 'Ethernet CSMAD'),
     (24, 'Loopback'),
     (53, 'Proprietary Virtual (Cisco VLAN L3)'),
@@ -20,19 +34,16 @@ ignore_interfaces_auth = [
     (136, 'Layer 3 IP VLAN'),
 ]
 
-register_check_parameters(
-    subgroup_networking,
-    'cisco_eigrp_interface',
-    _('Cisco EIGRP interface'),
-    Dictionary(
+
+def _parameter_valuespec_cisco_eigrp_interface():
+    return Dictionary(
         help=_(''),
         elements=[
             ('ignore_interfaces_auth',
              ListChoice(
                  title=_('no warning if EIRGP authentication not configured on selected interface types'),
-                 label=_('no warning if EIRGP authentication not configured on selected interface types'),
                  help=_('no warning if EIRGP authentication not configured on selected interface types'),
-                 choices=ignore_interfaces_auth,
+                 choices=_ignore_interfaces_auth,
                  default_value=[],
              )),
             ('no_auth_state',
@@ -47,12 +58,21 @@ register_check_parameters(
             ('md5_auth_state',
              MonitoringState(
                  title=_('State to report when interface uses MD5 authentication'),
-                 help=_('State if an EIGRP enabled interface uses an MD5 hash as authentication method. Default is warning'),
+                 help=_(
+                     'State if an EIGRP enabled interface uses an MD5 hash as authentication method. Default is warning'),
                  default_value=1,
              ),
              ),
         ],
-    ),
-    TextAscii(title=_('Cisco EIGRP interface')),
-    match_type='dict',
-)
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='cisco_eigrp_interface',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('Cisco EIGRP interface'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_cisco_eigrp_interface,
+        title=lambda: _('Cisco EIGRP interface'),
+    ))
diff --git a/web/plugins/wato/cisco_eigrp_peers.py b/web/plugins/wato/cisco_eigrp_peers.py
index 7d44d87..5ed6f97 100644
--- a/web/plugins/wato/cisco_eigrp_peers.py
+++ b/web/plugins/wato/cisco_eigrp_peers.py
@@ -1,35 +1,61 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
+#!/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 cisco_eigrp_peer WATO plugin
 #
-# Author: Th.L.
-# Date: 2017-12-25
-#
-#
-#
-#
-register_check_parameters(
-    subgroup_networking,
-    'cisco_eigrp_peers',
-    _('Cisco EIGRP peer'),
-    Dictionary(
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    Integer,
+    TextAscii,
+    Tuple,
+)
+
+from cmk.gui.plugins.wato import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+)
+
+
+def _parameter_valuespec_cisco_eigrp_peers():
+    return Dictionary(
         help=_(''),
         elements=[
             ('minuptime',
-             Integer(
-                 help=_('Set the time in seconds, a peer must be up before the peer is considered sable.'
-                        'If the peer uptime less then X, the check outcome is set to warning.'),
-                 title=_('Minimum uptime for peer. If uptime less, set check outcome to warning. Default is 1 day.'),
-                 default_value=86400,
-                 allow_empty=False,
-                 unit='seconds',
-                 minvalue=1,
-             ),
-             )
+             Tuple(
+                 title=_('Minimum uptime for peer. Default is 1/2 hours.'),
+                 help=_('Set the time in seconds, a peer must be up before the peer is considered stable.'
+                        'If the peer uptime less then X, the check outcome is set to warning/critical.'),
+                 elements=[
+                     Integer(title=_('Warning below'),
+                             unit='seconds',
+                             default_value=7200,
+                             help=_('The uptime in seconds below which a warning state is triggered. Default is 7200s'),
+                             ),
+                     Integer(title=_('Critical below'),
+                             unit='seconds',
+                             default_value=3600,
+                             help=_('The uptime in seconds below which a critical state is triggered. default is 3600s'),
+                             )
+                 ],
+             )),
         ],
-    ),
-    TextAscii(title=_('Cisco EIGRP peer')),
-    match_type='dict',
-)
\ No newline at end of file
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='cisco_eigrp_peers',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('Cisco EIGRP peer'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_cisco_eigrp_peers,
+        title=lambda: _('Cisco EIGRP peer'),
+    ))
diff --git a/web/plugins/wato/cisco_eigrp_topology_table.py b/web/plugins/wato/cisco_eigrp_topology_table.py
index 72e8da2..51644c2 100644
--- a/web/plugins/wato/cisco_eigrp_topology_table.py
+++ b/web/plugins/wato/cisco_eigrp_topology_table.py
@@ -1,37 +1,54 @@
-#!/usr/bin/python
-# -*- encoding: utf-8; py-indent-offset: 4 -*-
-
-#
-# Check_MK cisco_eigrp_topology_table WATO plugin
-#
-# Author: Th.L.
-# Date: 2017-12-27
+#!/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-27
 #
 #
+# Check_MK cisco_eigrp_topology_table WATO plugin
 #
+from cmk.gui.i18n import _
+from cmk.gui.valuespec import (
+    Dictionary,
+    ListChoice,
+    TextAscii,
+)
 
-nowarnon = [('siaroutes', 'Stuck in active (SIA) routes'),
+from cmk.gui.plugins.wato import (
+    CheckParameterRulespecWithItem,
+    rulespec_registry,
+    RulespecGroupCheckParametersNetworking,
+)
+
+_nowarnon = [('siaroutes', 'Stuck in active (SIA) routes'),
             ('activeroutes', 'Active routes')]
 
-register_check_parameters(
-    subgroup_networking,
-    'cisco_eigrp_topology_table',
-    _('Cisco EIGRP topology table'),
-    Dictionary(
+
+def _parameter_valuespec_cisco_eigrp_topology_table():
+    return Dictionary(
         help=_(''),
         elements=[
             ('nowarnon',
              ListChoice(
                  title=_('no warning if EIRGP SIA/active route found'),
-                 label=_('no warning if EIRGP SIA/active route found'),
                  help=_('no warning if EIRGP Stuck in active (SIA) / active route found'),
-                 choices=nowarnon,
+                 choices=_nowarnon,
                  default_value=[],
              ),
              )
         ],
-    ),
-    TextAscii(title=_('Cisco EIGRP topology table')),
-    match_type='dict',
-)
+    )
+
+
+rulespec_registry.register(
+    CheckParameterRulespecWithItem(
+        check_group_name='cisco_eigrp_topology_table',
+        group=RulespecGroupCheckParametersNetworking,
+        item_spec=lambda: TextAscii(title=_('Cisco EIGRP topology table'), ),
+        match_type='dict',
+        parameter_valuespec=_parameter_valuespec_cisco_eigrp_topology_table,
+        title=lambda: _('Cisco EIGRP topology table'),
+    ))
\ No newline at end of file
-- 
GitLab