diff --git a/brian_polling_manager/interface_stats/cli.py b/brian_polling_manager/interface_stats/cli.py
index 3b56fdd88432815e4e7a4e79ef841979481f59b0..8783169ad64bc46b088f21fb91e2fb515cd36d0e 100644
--- a/brian_polling_manager/interface_stats/cli.py
+++ b/brian_polling_manager/interface_stats/cli.py
@@ -10,11 +10,10 @@ from typing import Iterable, List, Sequence
 import click
 import jsonschema
 from brian_polling_manager.influx import influx_client
-from brian_polling_manager.interface_stats import vendors
+from brian_polling_manager.interface_stats import vendors, config
 from brian_polling_manager.interface_stats.vendors import Vendor, juniper, nokia
 from brian_polling_manager.inventory import load_interfaces
-
-from . import config
+from lxml import etree
 
 logger = logging.getLogger(__file__)
 
@@ -104,14 +103,10 @@ def write_points_to_stdout(points, influx_params, stream=sys.stdout, **_):
 
 
 def get_netconf(router_name, vendor: Vendor, ssh_params: dict, **kwargs):
-    if vendor == Vendor.JUNIPER:
-        return juniper.get_netconf_interface_info(
-            router_name, ssh_params=ssh_params, **kwargs
-        )
-    else:
-        return nokia.get_netconf_interface_info(
-            router_name, ssh_params=ssh_params, **kwargs
-        )
+    module = juniper if vendor == Vendor.JUNIPER else nokia
+    return module.get_netconf_interface_info(
+        router_name, ssh_params=ssh_params, **kwargs
+    )
 
 
 def validate_router_hosts(
@@ -123,13 +118,14 @@ def validate_router_hosts(
     if inprov_hosts is None:
         return True
 
+    if vendor == Vendor.NOKIA:
+        logger.info(f"Skipping validation for Nokia host(s) {' '.join(hostnames)}")
+        return True
+
     logger.info(
         f"Validating hosts {' '.join(hostnames)} using providers {inprov_hosts}"
     )
-    if vendor == Vendor.NOKIA:
-        all_fqdns = []
-    else:
-        all_fqdns = {ifc["router"] for ifc in load_interfaces_(inprov_hosts)}
+    all_fqdns = {ifc["router"] for ifc in load_interfaces_(inprov_hosts)}
 
     extra_fqdns = set(hostnames) - set(all_fqdns)
     if extra_fqdns:
@@ -141,34 +137,24 @@ def validate_router_hosts(
 
 
 def process_router(
-    router_fqdn: str,
-    vendor: Vendor,
-    app_config_params: dict,
-    output: OutputMethod,
+    router_fqdn: str, vendor: Vendor, app_config_params: dict, output: OutputMethod
 ):
-    if vendor == Vendor.JUNIPER:
-        return process_juniper_router(router_fqdn, app_config_params, output)
-    else:
-        return process_nokia_router(router_fqdn, app_config_params, output)
 
+    logger.info(f"Processing {vendor.value.capitalize()} router {router_fqdn}")
 
-def process_juniper_router(
-    router_fqdn: str, app_config_params: dict, output: OutputMethod
-):
-    logger.info(f"Processing Juniper router {router_fqdn}")
-
-    ssh_params = app_config_params[Vendor.JUNIPER.value]
-    document = get_netconf(router_fqdn, vendor=Vendor.JUNIPER, ssh_params=ssh_params)
+    ssh_params = app_config_params[vendor.value]
+    document = get_netconf(router_fqdn, vendor=vendor, ssh_params=ssh_params)
     timestamp = datetime.now()
 
     influx_params = app_config_params["influx"]["brian-counters"]
     logger.info("Processing Brian points...")
     points = list(
-        _juniper_brian_points(
+        _brian_points(
             router_fqdn=router_fqdn,
             netconf_doc=document,
             timestamp=timestamp,
             measurement_name=influx_params["measurement"],
+            vendor=vendor,
         )
     )
     _log_interface_points_sorted(points)
@@ -177,11 +163,12 @@ def process_juniper_router(
     influx_params = app_config_params["influx"]["error-counters"]
     logger.info("Processing Error points...")
     points = list(
-        _juniper_error_points(
+        _error_points(
             router_fqdn=router_fqdn,
             netconf_doc=document,
             timestamp=timestamp,
             measurement_name=influx_params["measurement"],
+            vendor=vendor,
         )
     )
 
@@ -189,6 +176,34 @@ def process_juniper_router(
     write_points(points, influx_params=influx_params, output=output)
 
 
+def _brian_points(
+    router_fqdn: str,
+    netconf_doc: etree.Element,
+    timestamp: datetime,
+    measurement_name: str,
+    vendor: Vendor,
+):
+    module = juniper if vendor == Vendor.JUNIPER else nokia
+    interfaces = module.interface_counters(netconf_doc)
+    yield from vendors.brian_points(
+        router_fqdn, interfaces, timestamp, measurement_name
+    )
+
+
+def _error_points(
+    router_fqdn: str,
+    netconf_doc: etree.Element,
+    timestamp: datetime,
+    measurement_name: str,
+    vendor: Vendor,
+):
+    module = juniper if vendor == Vendor.JUNIPER else nokia
+    interfaces = module.interface_counters(netconf_doc)
+    yield from vendors.error_points(
+        router_fqdn, interfaces, timestamp, measurement_name
+    )
+
+
 def _log_interface_points_sorted(points: Sequence[dict], point_kind=""):
     N_COLUMNS = 5
     num_points = len(points)
@@ -201,31 +216,12 @@ def _log_interface_points_sorted(points: Sequence[dict], point_kind=""):
 
     interfaces = sorted(p["tags"]["interface_name"] for p in points)
     longest_ifc = max(len(i) for i in interfaces)
-    for n in range(len(interfaces) // N_COLUMNS + 1):
+    ifc_count = len(interfaces)
+    for n in range(ifc_count // N_COLUMNS + (ifc_count % N_COLUMNS > 0)):
         ifc_slice = interfaces[n * N_COLUMNS : (n + 1) * N_COLUMNS]
         logger.info("    ".join(i.ljust(longest_ifc) for i in ifc_slice))
 
 
-def _juniper_brian_points(router_fqdn, netconf_doc, timestamp, measurement_name):
-    interfaces = juniper.interface_counters(netconf_doc)
-    yield from vendors.brian_points(
-        router_fqdn, interfaces, timestamp, measurement_name
-    )
-
-
-def _juniper_error_points(router_fqdn, netconf_doc, timestamp, measurement_name):
-    interfaces = juniper.interface_counters(netconf_doc)
-    yield from vendors.error_points(
-        router_fqdn, interfaces, timestamp, measurement_name
-    )
-
-
-def process_nokia_router(
-    router_fqdn: str, app_config_params: dict, output: OutputMethod
-):
-    logger.warning(f"skipping Nokia router {router_fqdn}")
-
-
 def main(
     app_config_params: dict,
     router_fqdns: List[str],
@@ -250,9 +246,9 @@ def main(
                 app_config_params=app_config_params,
                 output=output,
             )
-        except Exception as e:
+        except Exception:
             logger.exception(
-                f"Error while processing {vendor_str} {router}", exc_info=e
+                f"Error while processing {vendor_str.capitalize()} router {router}"
             )
             error_count += 1
 
diff --git a/brian_polling_manager/interface_stats/vendors/__init__.py b/brian_polling_manager/interface_stats/vendors/__init__.py
index 1b7f72da24c0a5f9f4f4aef66769ab834dd94652..801e635060f1bb795eafaccc73ec55203c058c88 100644
--- a/brian_polling_manager/interface_stats/vendors/__init__.py
+++ b/brian_polling_manager/interface_stats/vendors/__init__.py
@@ -5,8 +5,7 @@ from .common import (
     error_points,
     BRIAN_POINT_FIELDS_SCHEMA,
     ERROR_POINT_FIELDS_SCHEMA,
-    PHYSICAL_INTERFACE_COUNTER_SCHEMA,
-    LOGICAL_INTERFACE_COUNTER_SCHEMA,
+    INTERFACE_COUNTER_SCHEMA,
 )
 
 
@@ -18,8 +17,7 @@ class Vendor(enum.Enum):
 __all__ = [
     "BRIAN_POINT_FIELDS_SCHEMA",
     "ERROR_POINT_FIELDS_SCHEMA",
-    "PHYSICAL_INTERFACE_COUNTER_SCHEMA",
-    "LOGICAL_INTERFACE_COUNTER_SCHEMA",
+    "INTERFACE_COUNTER_SCHEMA",
     "brian_points",
     "error_points",
     "Vendor",
diff --git a/brian_polling_manager/interface_stats/vendors/common.py b/brian_polling_manager/interface_stats/vendors/common.py
index 8f85efc37090ece3968e8b03c064477e45351f1f..91e08dcd3ba0489aaf15ab6677a8b02256b27c53 100644
--- a/brian_polling_manager/interface_stats/vendors/common.py
+++ b/brian_polling_manager/interface_stats/vendors/common.py
@@ -1,95 +1,14 @@
+import contextlib
 import logging
 from functools import partial
+import ncclient.manager
+from lxml import etree
 
 logger = logging.getLogger(__name__)
 
-PHYSICAL_INTERFACE_COUNTER_SCHEMA = {
-    "$schema": "https://json-schema.org/draft/2020-12/schema",
-    "definitions": {
-        "brian-counters": {
-            "type": "object",
-            "properties": {
-                "ingressOctets": {"type": "integer"},
-                "ingressPackets": {"type": "integer"},
-                "egressOctets": {"type": "integer"},
-                "egressPackets": {"type": "integer"},
-                "ingressOctetsv6": {"type": "integer"},
-                "ingressPacketsv6": {"type": "integer"},
-                "egressOctetsv6": {"type": "integer"},
-                "egressPacketsv6": {"type": "integer"},
-                "ingressErrors": {"type": "integer"},
-                "egressErrors": {"type": "integer"},
-                "ingressDiscards": {"type": "integer"},
-            },
-            "required": [
-                "ingressOctets",
-                "ingressPackets",
-                "egressOctets",
-                "egressPackets",
-            ],
-            "additionalProperties": False,
-        },
-        "error-counters": {
-            "type": "object",
-            "properties": {
-                "bit_error_seconds": {"type": "integer"},
-                "errored_blocks_seconds": {"type": "integer"},
-                "input_crc_errors": {"type": "integer"},
-                "input_fifo_errors": {"type": "integer"},
-                "input_total_errors": {"type": "integer"},
-                "input_discards": {"type": "integer"},
-                "input_drops": {"type": "integer"},
-                "output_drops": {"type": "integer"},
-                "output_crc_errors": {"type": "integer"},
-                "output_fifo_errors": {"type": "integer"},
-                "output_total_errors": {"type": "integer"},
-                "input_framing_errors": {"type": "integer"},
-                "output_resource_errors": {"type": "integer"},
-                "input_resource_errors": {"type": "integer"},
-                "output_collisions": {"type": "integer"},
-            },
-            "additionalProperties": False,
-        },
-    },
-    "type": "object",
-    "properties": {
-        "name": {"type": "string"},
-        "brian": {"$ref": "#/definitions/brian-counters"},
-        "errors": {"$ref": "#/definitions/error-counters"},
-    },
-    "required": ["name", "brian"],
-    "additionalProperties": False,
-}
+DEFAULT_NETCONF_PORT = 830
+
 
-LOGICAL_INTERFACE_COUNTER_SCHEMA = {
-    "$schema": "https://json-schema.org/draft/2020-12/schema",
-    "type": "object",
-    "properties": {
-        "name": {"type": "string"},
-        "brian": {
-            "type": "object",
-            "properties": {
-                "ingressOctets": {"type": "integer"},
-                "ingressPackets": {"type": "integer"},
-                "egressOctets": {"type": "integer"},
-                "egressPackets": {"type": "integer"},
-                "ingressOctetsv6": {"type": "integer"},
-                "ingressPacketsv6": {"type": "integer"},
-                "egressOctetsv6": {"type": "integer"},
-                "egressPacketsv6": {"type": "integer"},
-            },
-            "required": [
-                "ingressOctets",
-                "ingressPackets",
-                "egressOctets",
-                "egressPackets",
-            ],
-            "additionalProperties": False,
-        },
-    },
-    "required": ["name", "brian"],
-    "additionalProperties": False,
-}
 BRIAN_POINT_FIELDS_SCHEMA = {
     "$schema": "https://json-schema.org/draft/2020-12/schema",
     "type": "object",
@@ -115,61 +34,6 @@ BRIAN_POINT_FIELDS_SCHEMA = {
     "additionalProperties": False,
 }
 
-# TODO (POL1-798): unify the counter schemas
-NOKIA_INTERFACE_COUNTER_SCHEMA = {
-    "$schema": "https://json-schema.org/draft/2020-12/schema",
-    "definitions": {
-        "brian-counters": {
-            "type": "object",
-            "properties": {
-                "ingressOctets": {"type": "integer"},
-                "ingressPackets": {"type": "integer"},
-                "egressOctets": {"type": "integer"},
-                "egressPackets": {"type": "integer"},
-                "ingressErrors": {"type": "integer"},
-                "egressErrors": {"type": "integer"},
-                "ingressDiscards": {"type": "integer"},
-                "egressDiscards": {"type": "integer"},
-            },
-            "required": [
-                "ingressOctets",
-                "ingressPackets",
-                "egressOctets",
-                "egressPackets",
-                "ingressErrors",
-                "egressErrors",
-                "ingressDiscards",
-                "egressDiscards",
-            ],
-            "additionalProperties": False,
-        },
-        "error-counters": {
-            "type": "object",
-            "properties": {
-                "input_discards": {"type": "integer"},
-                "output_discards": {"type": "integer"},
-                "output_total_errors": {"type": "integer"},
-            },
-            "required": [
-                "input_discards",
-                "output_discards",
-                "output_total_errors",
-            ],
-            "additionalProperties": False,
-
-            "additionalProperties": False,
-        },
-    },
-    "type": "object",
-    "properties": {
-        "name": {"type": "string"},
-        "brian": {"$ref": "#/definitions/brian-counters"},
-        "errors": {"$ref": "#/definitions/error-counters"},
-    },
-    "required": ["name", "brian"],
-    "additionalProperties": False,
-}
-
 
 ERROR_POINT_FIELDS_SCHEMA = {
     "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -178,19 +42,36 @@ ERROR_POINT_FIELDS_SCHEMA = {
         "bit_error_seconds": {"type": "integer"},
         "errored_blocks_seconds": {"type": "integer"},
         "input_crc_errors": {"type": "integer"},
-        "input_fifo_errors": {"type": "integer"},
-        "input_total_errors": {"type": "integer"},
         "input_discards": {"type": "integer"},
         "input_drops": {"type": "integer"},
-        "output_drops": {"type": "integer"},
-        "output_crc_errors": {"type": "integer"},
-        "output_fifo_errors": {"type": "integer"},
-        "output_total_errors": {"type": "integer"},
+        "input_fifo_errors": {"type": "integer"},
         "input_framing_errors": {"type": "integer"},
-        "output_resource_errors": {"type": "integer"},
         "input_resource_errors": {"type": "integer"},
+        "input_total_errors": {"type": "integer"},
         "output_collisions": {"type": "integer"},
+        "output_crc_errors": {"type": "integer"},
+        "output_discards": {"type": "integer"},
+        "output_drops": {"type": "integer"},
+        "output_fifo_errors": {"type": "integer"},
+        "output_resource_errors": {"type": "integer"},
+        "output_total_errors": {"type": "integer"},
+    },
+    "additionalProperties": False,
+}
+
+INTERFACE_COUNTER_SCHEMA = {
+    "$schema": "https://json-schema.org/draft/2020-12/schema",
+    "definitions": {
+        "brian-counters": BRIAN_POINT_FIELDS_SCHEMA,
+        "error-counters": ERROR_POINT_FIELDS_SCHEMA,
+    },
+    "type": "object",
+    "properties": {
+        "name": {"type": "string"},
+        "brian": {"$ref": "#/definitions/brian-counters"},
+        "errors": {"$ref": "#/definitions/error-counters"},
     },
+    "required": ["name", "brian"],
     "additionalProperties": False,
 }
 
@@ -199,8 +80,7 @@ def _counters_to_point(
     interface, router_fqdn, timestamp, measurement, counters_name, required=False
 ):
     """
-    :param interface: either a PHYSICAL_INTERFACE_COUNTER_SCHEMA or
-        LOGICAL_INTERFACE_COUNTER_SCHEMA object
+    :param interface: an instance of INTERFACE_COUNTER_SCHEMA
     :param router_fqdn: ``hostname`` tag to be set in the generated points
     :param measurement: the measurement where the point will be written
     :param counter_name: the desired set of counters (either ``brian`` or ``errors``)
@@ -225,8 +105,7 @@ def brian_points(router_fqdn, interfaces, timestamp, measurement_name):
     returns an interable of points that can be written to influxdb
 
     :param router_fqdn: 'hostname' tag to be set in the generated points
-    :param interfaces: an iterable of PHYSICAL_INTERFACE_COUNTER_SCHEMA or
-        LOGICAL_INTERFACE_COUNTER_SCHEMA
+    :param interfaces: an iterable of INTERFACE_COUNTER_SCHEMA
     :param timestamp: timestamp to put in the generated points
     :param measurement_name: measurement name to put in the generated points
     :return:
@@ -247,8 +126,7 @@ def error_points(router_fqdn, interfaces, timestamp, measurement_name):
     returns an interable of points that can be written to influxdb
 
     :param router_fqdn: 'hostname' tag to be set in the generated points
-    :param interfaces: an iterable of PHYSICAL_INTERFACE_COUNTER_SCHEMA or
-        LOGICAL_INTERFACE_COUNTER_SCHEMA
+    :param interfaces: an iterable of INTERFACE_COUNTER_SCHEMA
     :param timestamp: timestamp to put in the generated points
     :param measurement_name: measurement name to put in the generated points
     :return:
@@ -264,20 +142,6 @@ def error_points(router_fqdn, interfaces, timestamp, measurement_name):
     return filter(lambda r: r is not None, map(point_creator, interfaces))
 
 
-def _read_counter(node, path, transform, required=False):
-    if isinstance(path, str):
-        path = [path]
-    for p in path:
-        _elems = node.xpath(p + "/text()")
-        if _elems:
-            if len(_elems) > 1:
-                logger.warning(f"found more than one {p} in {node}")
-            return transform(_elems[0])
-
-    if required:
-        logger.error(f"required path {p} not found in {node}")
-
-
 def parse_interface_xml(node, struct: dict, defaults=None):
     """
     struct should be one of:
@@ -304,3 +168,34 @@ def parse_interface_xml(node, struct: dict, defaults=None):
             continue
         result[key] = parsed
     return result or None
+
+
+def _read_counter(node, path, transform, required=False):
+    if isinstance(path, str):
+        path = [path]
+    for p in path:
+        _elems = node.xpath(p + "/text()")
+        if _elems:
+            if len(_elems) > 1:
+                logger.warning(f"found more than one {p} in {node}")
+            return transform(_elems[0])
+
+    if required:
+        logger.error(f"required path {p} not found in {node}")
+
+
+@contextlib.contextmanager
+def netconf_connect(hostname: str, ssh_params: dict, **kwargs):
+    params = {"host": hostname, **kwargs, **ssh_params}
+    if "port" not in params:
+        params["port"] = DEFAULT_NETCONF_PORT
+    conn = ncclient.manager.connect(**params)
+    yield conn
+
+
+def remove_xml_namespaces(xml: str):
+    etree_doc = etree.fromstring(xml)
+    for elem in etree_doc.iter():
+        elem.tag = etree.QName(elem).localname
+    etree.cleanup_namespaces(etree_doc)
+    return etree_doc
diff --git a/brian_polling_manager/interface_stats/vendors/juniper.py b/brian_polling_manager/interface_stats/vendors/juniper.py
index 73b7a9e55cf571ff05923b370193875e8a88c219..2dd61410dbd5e1e81b9e0f35805608c9ad855e26 100644
--- a/brian_polling_manager/interface_stats/vendors/juniper.py
+++ b/brian_polling_manager/interface_stats/vendors/juniper.py
@@ -1,17 +1,18 @@
 import logging
 import pathlib
 
+from brian_polling_manager.interface_stats.vendors.common import (
+    netconf_connect,
+    parse_interface_xml,
+    remove_xml_namespaces,
+)
 from lxml import etree
-import ncclient.manager
-from ncclient.devices.junos import JunosDeviceHandler
-from ncclient.xml_ import NCElement
-
-from brian_polling_manager.interface_stats.vendors.common import parse_interface_xml
 
 logger = logging.getLogger(__name__)
 
-DEFAULT_NETCONF_PORT = 830
-DEFAULT_NETCONF_CONNECT_TIMEOUT = 5  # seconds
+NCCLIENT_PARAMS = {
+    "timeout": 5,
+}
 
 PHYSICAL_INTERFACE_COUNTERS = {
     "__defaults__": {"transform": int, "required": False},
@@ -42,7 +43,7 @@ PHYSICAL_INTERFACE_COUNTERS = {
         "ingressErrors": {"path": "./input-error-list/input-errors"},
         "egressErrors": {"path": "./output-error-list/output-errors"},
         "ingressDiscards": {"path": "./input-error-list/input-discards"},
-        # These error counters are unused, but perhaps in the future we want to output
+        # These counters are unused, but perhaps in the future we want to output
         # them as well
         # "l2_input_broadcast": {"path": "./ethernet-mac-statistics/input-broadcasts"},
         # "l2_input_multicast": {"path": "./ethernet-mac-statistics/input-multicasts"},
@@ -65,6 +66,7 @@ PHYSICAL_INTERFACE_COUNTERS = {
         "output_resource_errors": {
             "path": "./output-error-list/output-resource-errors"
         },
+        "output_discards": {"path": "./output-error-list/output-discards"},
         "output_fifo_errors": {"path": "./output-error-list/output-fifo-errors"},
         "output_collisions": {"path": "./output-error-list/output-collisions"},
         "input_crc_errors": {"path": "./ethernet-mac-statistics/input-crc-errors"},
@@ -171,67 +173,21 @@ def _logical_interface_counters(ifc_doc):
 
 def interface_counters(ifc_doc):
     yield from _physical_interface_counters(ifc_doc)
-
-    # [2024-03-21] We currently have no definition for error points on logical
-    # interfaces, so returning these interfaces when writing error points
-    # is essentially a no-op. Perhaps in the future we will
-    # get a definition for errors on logical interfaces
     yield from _logical_interface_counters(ifc_doc)
 
 
-def get_netconf_interface_info(router_name, ssh_params, timeout=10):
+def get_netconf_interface_info(router_name, ssh_params):
     request = etree.Element("get-interface-information")
     request.append(etree.Element("extensive"))
-    response = _rpc(
-        router_name,
-        ssh_params=ssh_params,
-        command=request,
-        manager_params={"timeout": timeout},
-    )
-    return _remove_ns(response)
-
-
-def _remove_ns(rpc_response):
-    junos_dev_handler = JunosDeviceHandler(
-        device_params={"name": "junos", "local": False}
-    )
-    return NCElement(
-        rpc_response, junos_dev_handler.transform_reply()
-    ).remove_namespaces(rpc_response.xml)
-
-
-def _rpc(
-    router_name: str,
-    ssh_params: dict,
-    manager_params: dict,
-    command: etree.Element,
-    port=DEFAULT_NETCONF_PORT,
-    timeout=DEFAULT_NETCONF_CONNECT_TIMEOUT,
-):
-    """
-    :param router_name: router fqdn
-    :param ssh_params: 'juniper' element from app config
-    :param command: an lxml etree element
-    :param port: the port to connect to
-    :param timeout: a timeout in seconds
-    :return: the router netconf rpc reponse as an lxml.Element
-    """
-    params = {
-        "host": router_name,
-        "port": port,
-        "timeout": timeout,
-        **ssh_params,
-        **manager_params,
-    }
-
-    with ncclient.manager.connect(**params) as router:
-        logger.debug(f"sending rpc command: {etree.tostring(command)}")
-        return router.rpc(command)
-
-
-def get_netconf_interface_info_from_source_dir(
-    router_name: str, source_dir: str, *_, **__
-):
+
+    with netconf_connect(
+        hostname=router_name, ssh_params=ssh_params, **NCCLIENT_PARAMS
+    ) as conn:
+        response = conn.rpc(request)
+    return remove_xml_namespaces(response.xml)
+
+
+def get_netconf_interface_info_from_source_dir(router_name: str, source_dir: str):
     file = pathlib.Path(source_dir) / f"{router_name}-interface-info.xml"
     if not file.is_file():
         raise ValueError(f"file {file} is not a valid file")
diff --git a/brian_polling_manager/interface_stats/vendors/nokia.py b/brian_polling_manager/interface_stats/vendors/nokia.py
index b4834e02163df75fa6b2b1306ff36c4267ac0e78..a4179adc006008644c33254df4b5c49e243baf0e 100644
--- a/brian_polling_manager/interface_stats/vendors/nokia.py
+++ b/brian_polling_manager/interface_stats/vendors/nokia.py
@@ -1,151 +1,112 @@
-"""
-
-"""
-import contextlib
 import logging
 import pathlib
-import time
-import typing
-
+from brian_polling_manager.interface_stats.vendors.common import (
+    netconf_connect,
+    parse_interface_xml,
+    remove_xml_namespaces,
+)
 from lxml import etree
-import ncclient.manager
-
-from brian_polling_manager.interface_stats.vendors.common import parse_interface_xml
-
-if typing.TYPE_CHECKING:
-    from ncclient.lxml_ import NCElement
 
 logger = logging.getLogger(__name__)
 
-STATE_NS = 'urn:nokia.com:sros:ns:yang:sr:state'
-
-# TODO: decide if these are really global
-DEFAULT_NETCONF_PORT = 830
-# cf. POL1-799
-DEFAULT_NETCONF_CONNECT_TIMEOUT = 60  # seconds
-# DEFAULT_NETCONF_CONNECT_TIMEOUT = 5  # seconds
-ENDPOINT_TYPES = {'port', 'lag'}
-
 
-@contextlib.contextmanager
-def _connection(hostname: str, ssh_params: dict, port: int = DEFAULT_NETCONF_PORT):
-    params = {
-        'host': hostname,
-        'port': port,
-        'device_params': {'name': 'sros'},
-        'nc_params': {'capabilities': ['urn:nokia.com:nc:pysros:pc']},
-        'timeout': DEFAULT_NETCONF_CONNECT_TIMEOUT
-    }
-    params.update(ssh_params)
-
-    conn = ncclient.manager.connect(**params)
-    conn.async_mode = False
-    yield conn
-
-
-def _remove_ns(nc_doc: 'NCElement'):
-    # convert to etree
-    etree_doc = etree.fromstring(nc_doc.tostring.decode('utf-8'))
-    for elem in etree_doc.getiterator():
-        elem.tag = etree.QName(elem).localname
-    etree.cleanup_namespaces(etree_doc)
-    return etree_doc
+NCCLIENT_PARAMS = {
+    "device_params": {"name": "sros"},
+    "nc_params": {"capabilities": ["urn:nokia.com:nc:pysros:pc"]},
+    "timeout": 60,
+}
+
+INTERFACE_COUNTERS = {
+    "__defaults__": {"transform": int, "required": False},
+    "name": {
+        "path": ["./lag-name", "./port-id"],
+        "transform": lambda v: str(v).strip(),
+    },
+    "brian": {
+        "ingressOctets": {"path": "./statistics/in-octets", "required": True},
+        "ingressPackets": {
+            "path": "./statistics/in-packets",
+            "required": True,
+        },
+        "egressOctets": {"path": "./statistics/out-octets", "required": True},
+        "egressPackets": {"path": "./statistics/out-packets", "required": True},
+        "ingressErrors": {"path": "./statistics/in-errors"},
+        "egressErrors": {"path": "./statistics/out-errors"},
+        "ingressDiscards": {"path": "./statistics/in-discards"},
+    },
+    "errors": {
+        "output_total_errors": {"path": "./statistics/out-errors"},
+        "input_total_errors": {"path": "./statistics/in-errors"},
+        "input_discards": {"path": "./statistics/in-discards"},
+        "output_discards": {"path": "./statistics/out-discards"},
+    },
+}
+
+INTERFACE_COUNTERS_ALT = {
+    "__defaults__": {"transform": int, "required": False},
+    "name": {
+        "path": "./interface-name",
+        "transform": lambda v: str(v).strip(),
+    },
+    "brian": {
+        "ingressOctets": {"path": "./statistics/ip/in-octets", "required": True},
+        "ingressPackets": {
+            "path": "./statistics/ip/in-packets",
+            "required": True,
+        },
+        "egressOctets": {"path": "./statistics/ip/out-octets", "required": True},
+        "egressPackets": {"path": "./statistics/ip/out-packets", "required": True},
+        "ingressOctetsv6": {"path": "./ipv6/statistics/in-octets"},
+        "ingressPacketsv6": {"path": "./ipv6/statistics/in-packets"},
+        "egressOctetsv6": {"path": "./ipv6/statistics/out-octets"},
+        "egressPacketsv6": {"path": "./ipv6/statistics/out-packets"},
+    },
+    "errors": {"output_discards": {"path": "./statistics/ip/out-discard-packets"}},
+}
 
 
 def get_netconf_interface_info(router_name: str, ssh_params: dict):
+    STATE_NS = "urn:nokia.com:sros:ns:yang:sr:state"
 
-    def _filter(endpoint_type: str):
+    def query(*path: str):
         # https://github.com/nokia/pysros/blob/main/examples/show_port_counters.py
         # https://netdevops.me/2020/nokia-yang-tree-and-path-browser/
         # https://github.com/hellt/nokia-yangtree
-        _f = etree.Element('filter')
-        state = etree.SubElement(
-            _f,
-            f'{{{STATE_NS}}}state',
-            nsmap={'nokia-state': STATE_NS})
-        _ = etree.SubElement(state, f'{{{STATE_NS}}}{endpoint_type}')
-        # cf. POL1-799
-        # _ = etree.SubElement(_state, f'{{{STATE_NS}}}statistics')
-        return _f
-
-    start = time.time()
-    with _connection(hostname=router_name, ssh_params=ssh_params) as router:
-        # return {_ept: _remove_ns(router.get(filter=_filter(_ept))) for _ept in ENDPOINT_TYPES}
-        now = time.time()
-        logger.debug(f"seconds to connect ({router_name}: {now - start}")
-
-        rsp = {}
-        for _ept in ENDPOINT_TYPES:
-            start = now
-            logger.debug(f"Getting {router_name} {_ept} info")
-            rsp[_ept] = _remove_ns(router.get(filter=_filter(_ept)))
-            now = time.time()
-            logger.debug(f"   seconds to get {_ept} info: {now - start}")
-
-        return rsp
-
-
-def get_netconf_interface_info_from_source_dir(
-    router_name: str, source_dir: str, *_, **__
-):
-    file = pathlib.Path(source_dir) / f"{router_name}-ports.xml"
-    if not file.is_file():
-        raise ValueError(f"file {file} is not a valid file")
-    ports_doc = etree.fromstring(file.read_text())
-
-    file = pathlib.Path(source_dir) / f"{router_name}-lags.xml"
-    if not file.is_file():
-        raise ValueError(f"file {file} is not a valid file")
-    lags_doc = etree.fromstring(file.read_text())
 
-    return {
-        'port': ports_doc,
-        'lag': lags_doc
+        root = etree.Element("filter")
+        sub_elem = etree.SubElement(
+            root, f"{{{STATE_NS}}}state", nsmap={"nokia-state": STATE_NS}
+        )
+        for p in path:
+            sub_elem = etree.SubElement(sub_elem, f"{{{STATE_NS}}}{p}")
+        return root
+
+    def get_xml(conn, query_):
+        response = conn.get(filter=query_)
+        return remove_xml_namespaces(response.tostring.decode("utf-8"))
+
+    queries = {
+        "port": query("port"),
+        "lag": query("lag"),
+        "router-interface": query("router", "interface"),
     }
+    with netconf_connect(
+        hostname=router_name, ssh_params=ssh_params, **NCCLIENT_PARAMS
+    ) as conn:
+        return {ept: get_xml(conn, q) for ept, q in queries.items()}
 
 
-def _counter_parse_config(name_tag: str):
-    """
-    the stats info for both port and lag are the same, only the
-    name we use for reference is different, so the parsing is nearly
-    identical
+def get_netconf_interface_info_from_source_dir(router_name: str, source_dir: str):
+    def read_doc_or_raise(name: str):
+        file = pathlib.Path(source_dir) / name
+        if not file.is_file():
+            raise ValueError(f"file {file} is not a valid file")
 
-    :param name_tag: either 'port-id' or 'lag-name'
-    :return:
-    """
-    # sanity: special-purpose method for only these 2 cases
-    assert name_tag in ('port-id', 'lag-name')
+        return etree.fromstring(file.read_text())
 
     return {
-        "__defaults__": {"transform": int, "required": False},
-        "name": {"path": f"./{name_tag}", "transform": lambda v: str(v).strip()},
-        "brian": {
-            "ingressOctets": {
-                "path": "./statistics/in-octets",
-                "required": True
-            },
-            "ingressPackets": {
-                "path": "./statistics/in-packets",
-                "required": True,
-            },
-            "egressOctets": {
-                "path": "./statistics/out-octets",
-                "required": True
-            },
-            "egressPackets": {
-                "path": "./statistics/out-packets",
-                "required": True
-            },
-            "ingressErrors": {"path": "./statistics/in-errors"},
-            "egressErrors": {"path": "./statistics/out-errors"},
-            "ingressDiscards": {"path": "./statistics/in-discards"},
-            "egressDiscards": {"path": "./statistics/out-discards"},
-        },
-        "errors": {
-            "output_total_errors": {"path": "./statistics/out-errors"},
-            "input_discards": {"path": "./statistics/in-discards"},
-            "output_discards": {"path": "./statistics/out-discards"},
-        },
+        key: read_doc_or_raise(f"{router_name}-{key}s.xml")
+        for key in ["port", "lag", "router-interface"]
     }
 
 
@@ -155,16 +116,8 @@ def _port_counters(state_doc: etree.Element):
     :return: counters for all monitored ports
     """
 
-    parse_config = _counter_parse_config('port-id')
-
-    for port in state_doc.xpath(
-        "//data/state/port["
-        ' normalize-space(oper-state)="up"'
-        "]"
-    ):
-        result = parse_interface_xml(port, parse_config)
-        assert result
-        yield result
+    for elem in state_doc.xpath("//data/state/port"):
+        yield parse_interface_xml(elem, INTERFACE_COUNTERS)
 
 
 def _lag_counters(state_doc: etree.Element):
@@ -173,16 +126,18 @@ def _lag_counters(state_doc: etree.Element):
     :return: counters for all monitored lags
     """
 
-    parse_config = _counter_parse_config('lag-name')
+    for elem in state_doc.xpath("//data/state/lag"):
+        yield parse_interface_xml(elem, INTERFACE_COUNTERS)
+
+
+def _router_interface_counters(state_doc: etree.Element):
+    """
+    :param state_doc: /nokia-state:state/router/interface yang node
+    :return: counters for all monitored "router interfaces"
+    """
 
-    for port in state_doc.xpath(
-        "//data/state/lag["
-        ' normalize-space(oper-state)="up"'
-        "]"
-    ):
-        result = parse_interface_xml(port, parse_config)
-        assert result
-        yield result
+    for elem in state_doc.xpath("//data/state/router/interface"):
+        yield parse_interface_xml(elem, INTERFACE_COUNTERS_ALT)
 
 
 def interface_counters(raw_counter_docs: dict):
@@ -191,27 +146,6 @@ def interface_counters(raw_counter_docs: dict):
     :param raw_counter_docs: output of a call to get_netconf_interface_info
     :return: iterable of interface counters
     """
-    yield from _port_counters(raw_counter_docs['port'])
-    yield from _lag_counters(raw_counter_docs['lag'])
-
-
-if __name__ == '__main__':
-    from brian_polling_manager.interface_stats import config
-    import os
-    config_filename = os.path.join(
-        os.path.dirname(__file__),
-        '..', 'config-test.json')
-    with open(config_filename) as f:
-        params = config.load(f)
-
-    ROUTERS = [
-        'rt0.lon.uk.lab.office.geant.net',
-        'rt0.ams.nl.lab.office.geant.net'
-    ]
-
-    # rsp = get_interface_info_ncrpc(
-    raw_counter_docs = get_netconf_interface_info(
-        router_name=ROUTERS[0],
-        ssh_params=params['nokia'])
-
-    print(interface_counters(raw_counter_docs))
+    yield from _port_counters(raw_counter_docs["port"])
+    yield from _lag_counters(raw_counter_docs["lag"])
+    yield from _router_interface_counters(raw_counter_docs["router-interface"])
diff --git a/test/interface_stats/conftest.py b/test/interface_stats/conftest.py
index bb9159cd43fc55dcb834dcc1cc27ccee7ad1f522..ed0a766c2d78f5600b04a79682f44d0ac4e594fc 100644
--- a/test/interface_stats/conftest.py
+++ b/test/interface_stats/conftest.py
@@ -1,8 +1,8 @@
-import functools
 import json
 import pathlib
 from unittest.mock import patch
-from brian_polling_manager.interface_stats.vendors import juniper, nokia
+from brian_polling_manager.interface_stats import cli
+from brian_polling_manager.interface_stats.vendors import Vendor, juniper, nokia
 import pytest
 
 
@@ -30,38 +30,21 @@ def data_dir():
     return DATA_DIR
 
 
-@pytest.fixture(autouse=True)
-def mocked_juniper_get_netconf_interface_info(data_dir):
-    patcher = patch.object(
-        juniper,
-        "get_netconf_interface_info",
-        functools.partial(
-            juniper.get_netconf_interface_info_from_source_dir, source_dir=data_dir
-        ),
-    )
-    patcher.start()
-    yield patcher
-    try:
-        patcher.stop()
-    except RuntimeError:  # already stopped
-        pass
-
-
-@pytest.fixture(autouse=True)
-def mocked_nokia_get_netconf_interface_info(data_dir):
-    patcher = patch.object(
-        nokia,
-        "get_netconf_interface_info",
-        functools.partial(
-            nokia.get_netconf_interface_info_from_source_dir, source_dir=data_dir
-        ),
-    )
-    patcher.start()
-    yield patcher
-    try:
-        patcher.stop()
-    except RuntimeError:  # already stopped
-        pass
+@pytest.fixture
+def mocked_get_netconf(data_dir):
+    def get_netconf(router_name, vendor, **_):
+        if vendor == Vendor.JUNIPER:
+            return juniper.get_netconf_interface_info_from_source_dir(
+                router_name, source_dir=data_dir
+            )
+
+        else:
+            return nokia.get_netconf_interface_info_from_source_dir(
+                router_name, source_dir=data_dir
+            )
+
+    with patch.object(cli, "get_netconf", side_effect=get_netconf) as mock:
+        yield mock
 
 
 def poller_interfaces():
diff --git a/test/interface_stats/data/capture-test-data-nokia.py b/test/interface_stats/data/capture-test-data-nokia.py
index 406d1b3e4d42cc4f616ff66a487ea02bf93a4793..783efe07a67bb04059a6ba09f2ac15557f991889 100644
--- a/test/interface_stats/data/capture-test-data-nokia.py
+++ b/test/interface_stats/data/capture-test-data-nokia.py
@@ -24,11 +24,10 @@ def load_estate_interface_info():
         logger.info(fqdn)
         raw_counter_docs = nokia.get_netconf_interface_info(router_name=fqdn, ssh_params=SSH_PARAMS)
 
-        file = pathlib.Path(__file__).parent / f"{fqdn}-ports.xml"
-        file.write_bytes(etree.tostring(raw_counter_docs['port']))
-
-        file = pathlib.Path(__file__).parent / f"{fqdn}-lags.xml"
-        file.write_bytes(etree.tostring(raw_counter_docs['lag']))
+        assert set(raw_counter_docs.keys()) ==  {"port", "lag", "router-interface"}
+        for key,doc in raw_counter_docs.items():
+            file = pathlib.Path(__file__).parent / f"{fqdn}-{key}s.xml"
+            file.write_bytes(etree.tostring(doc))
 
 
 if __name__ == "__main__":
diff --git a/test/interface_stats/data/capture-test-data.py b/test/interface_stats/data/capture-test-data.py
index 6f152cc68fa0af59ea8e85bc4e62b589adb7a851..fa85b905b6be96dc46bec55a197b16b4545425c3 100644
--- a/test/interface_stats/data/capture-test-data.py
+++ b/test/interface_stats/data/capture-test-data.py
@@ -1,7 +1,8 @@
 import concurrent.futures
 import pathlib
-from brian_polling_manager.interface_stats.services.netconf import (
-    JuniperNetconfProvider,
+
+from brian_polling_manager.interface_stats.vendors.juniper import (
+    get_netconf_interface_info,
 )
 from lxml import etree
 
@@ -66,20 +67,21 @@ ROUTERS = [
 ]
 
 
-def save_router_info(fqdn, provider: JuniperNetconfProvider):
+def save_router_info(fqdn, ssh_params: dict):
     print(fqdn)
     file = pathlib.Path(__file__).parent / f"{fqdn}-interface-info.xml"
-    doc = provider.get(fqdn)
+    doc = get_netconf_interface_info(router_name=fqdn, ssh_params=ssh_params)
     file.write_text(etree.tostring(doc))
 
 
 def load_estate_interface_info():
-    provider = JuniperNetconfProvider(
-        ssh_params={"host_verify": False, "ssh_config": "~/.ssh/config"}
-    )
     with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
         for r in ROUTERS:
-            executor.submit(save_router_info, r, provider)
+            executor.submit(
+                save_router_info,
+                r,
+                ssh_params={"host_verify": False, "ssh_config": "~/.ssh/config"},
+            )
         executor.shutdown(wait=True)
 
 
diff --git a/test/interface_stats/data/raw-response-sample.xml b/test/interface_stats/data/raw-response-juniper-sample.xml
similarity index 100%
rename from test/interface_stats/data/raw-response-sample.xml
rename to test/interface_stats/data/raw-response-juniper-sample.xml
diff --git a/test/interface_stats/data/raw-response-nokia-sample.xml b/test/interface_stats/data/raw-response-nokia-sample.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ecd5d4a6235775485d11b8fe3ea27979791935f3
--- /dev/null
+++ b/test/interface_stats/data/raw-response-nokia-sample.xml
@@ -0,0 +1,333 @@
+<rpc-reply xmlns="urn:ietf:params:xml:ns:netconf:base:1.0" message-id="urn:uuid:e6f0895c-876f-4bec-a018-8ad25e3f2605">
+  <data>
+    <state xmlns="urn:nokia.com:sros:ns:yang:sr:state">
+      <port>
+        <port-id>1/1/c1</port-id>
+        <down-reason/>
+        <far-end-port-id/>
+        <fp-number>1</fp-number>
+        <hardware-mac-address>00:00:00:00:00:00</hardware-mac-address>
+        <interface-group-handler-index>0</interface-group-handler-index>
+        <mac-chip-number>1</mac-chip-number>
+        <number-of-channels>0</number-of-channels>
+        <oper-state>down</oper-state>
+        <oper-state-last-changed>2024-04-04T09:57:28.2Z</oper-state-last-changed>
+        <otu-capable>false</otu-capable>
+        <physical-link>false</physical-link>
+        <port-class>connector</port-class>
+        <port-state>link-down</port-state>
+        <previous-state>link-down</previous-state>
+        <protocols-supported/>
+        <type>qsfp-dd-connector</type>
+        <user-assigned-mac>false</user-assigned-mac>
+        <rs-fec-oper-mode>none</rs-fec-oper-mode>
+        <licensed>true</licensed>
+        <if-index>1610899520</if-index>
+        <transceiver>
+          <equipped>false</equipped>
+        </transceiver>
+        <statistics>
+          <in-discards>0</in-discards>
+          <in-errors>0</in-errors>
+          <in-octets>0</in-octets>
+          <in-packets>0</in-packets>
+          <in-unknown-protocol-discards>0</in-unknown-protocol-discards>
+          <in-broadcast-packets>0</in-broadcast-packets>
+          <in-multicast-packets>0</in-multicast-packets>
+          <in-unicast-packets>0</in-unicast-packets>
+          <out-discards>0</out-discards>
+          <out-errors>0</out-errors>
+          <out-octets>0</out-octets>
+          <out-packets>0</out-packets>
+          <out-broadcast-packets>0</out-broadcast-packets>
+          <out-multicast-packets>0</out-multicast-packets>
+          <out-unicast-packets>0</out-unicast-packets>
+        </statistics>
+        <subscriber-management>
+          <statistics>
+            <ipv4-hosts>
+              <counter>ipcp</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>dhcp</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>arp</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>static</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>data-triggered</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>aaa</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>gtp</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>bonding</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>dhcp-bsm</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>static-bsm</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>dhcp-bsm-antispoof</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>static-bsm-antispoof</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>pfcp-ppp</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>pfcp-ipoe</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv4-hosts>
+              <counter>pfcp-fwa</counter>
+              <current-value>0</current-value>
+            </ipv4-hosts>
+            <ipv6-hosts>
+              <counter>ppp-slaac</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ppp-dhcp6-na</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ppp-dhcp6-pd</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ppp-dhcp6-pd-mngdrt</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-slaac</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-dhcp6-na</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-dhcp6-pd</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-dhcp6-pd-mngdrt</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-static-wan</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-static-pfx</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-data-wan</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-data-pfx</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-data-pfx-mngdrt</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-aaa</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-gtp</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-mngd-bonding</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-dhcp6-na-bsm</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>ipoe-dhcp6-pd-bsm</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ppp-slaac</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ppp-na</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ppp-pd</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ipoe-slaac</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ipoe-na</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-ipoe-pd</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-fwa-slaac</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-fwa-na</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <ipv6-hosts>
+              <counter>pfcp-fwa-pd</counter>
+              <current-value>0</current-value>
+            </ipv6-hosts>
+            <total-hosts>
+              <counter>subhosts</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>ppp</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>ipoe</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>ipv4</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>ipv6</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>ipv6-pd-mngdrt</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>l2tp-lac</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>l2tp-lns</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>internal</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>nonsub-traffic</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>dhcp-leases</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>dhcp6-leases</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <total-hosts>
+              <counter>pfcp</counter>
+              <current-value>0</current-value>
+            </total-hosts>
+            <sessions>
+              <counter>ppp-sessions-total-established</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-total-in-setup</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-local-pppoe</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-local-pppoeoa</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-local-pppoa</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-local-l2tp-lns</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-local-total</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-lac-pppoe</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-lac-pppoeoa</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-lac-pppoa</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-lac-l2tp-lts</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ppp-sessions-lac-total</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ipoe-sessions-total-established</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>ipoe-sessions-total-in-setup</counter>
+              <current-value>0</current-value>
+            </sessions>
+            <sessions>
+              <counter>subscribers-total</counter>
+              <current-value>0</current-value>
+            </sessions>
+          </statistics>
+        </subscriber-management>
+      </port>
+    </state>
+  </data>
+</rpc-reply>
diff --git a/test/interface_stats/data/rt0.ams.nl.lab.office.geant.net-router-interfaces.xml b/test/interface_stats/data/rt0.ams.nl.lab.office.geant.net-router-interfaces.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3907cfe5d7b6f3b6214ec1b717a04c74039d4841
--- /dev/null
+++ b/test/interface_stats/data/rt0.ams.nl.lab.office.geant.net-router-interfaces.xml
@@ -0,0 +1,661 @@
+<rpc-reply message-id="urn:uuid:5a05fb39-aaca-48e4-979c-2d6db6ba2c01">
+  <data>
+    <state>
+      <router>
+        <router-name>Base</router-name>
+        <interface>
+          <interface-name>system</interface-name>
+          <if-index>1</if-index>
+          <system-if-index>256</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>1500</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T07:53:41.8Z</last-oper-change>
+          <statistics>
+            <ip>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.6</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>0</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>0</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>0</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>0</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>0</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>0</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab::6</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab::6</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>lag-1.0</interface-name>
+          <if-index>2</if-index>
+          <system-if-index>1</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>9000</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T08:00:22.0Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>1</card>
+              <fp-number>1</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>3437402</out-packets>
+              <out-octets>1000435620</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>2891465</in-packets>
+              <in-octets>321980620</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>6054</out-packets>
+              <out-octets>2634617</out-octets>
+              <in-packets>6280</in-packets>
+              <in-octets>3101782</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>81402</icmp-in-msgs>
+                <icmp-in-errors>47768</icmp-in-errors>
+                <icmp-in-dest-unreachables>47768</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>33634</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>33633</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>33633</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>3177195</out-packets>
+              <out-octets>970038344</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.88</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv4-address>62.40.119.89</ipv4-address>
+                <oper-state>up</oper-state>
+                <mac-address>b2:a8:6e:3e:f4:b8</mac-address>
+                <type>dynamic</type>
+                <timer>13974</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>18601</icmp6-in-msgs>
+                <icmp6-in-errors>403</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>403</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>1605</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>16593</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>18198</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>16593</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>1605</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <link-local-address>
+              <oper-address>fe80::1ac3:ff:fe91:fe59</oper-address>
+              <address-state>preferred</address-state>
+            </link-local-address>
+            <statistics>
+              <out-packets>260207</out-packets>
+              <out-octets>30397276</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab:2::31</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab:2::31</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv6-address>fe80::b2a8:6eff:fe3e:f4b8</ipv6-address>
+                <state>delay</state>
+                <is-router>true</is-router>
+                <mtu>9000</mtu>
+                <mac-address>b2:a8:6e:3e:f4:b8</mac-address>
+                <type>dynamic</type>
+                <timer>4</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>lag-2.0</interface-name>
+          <if-index>3</if-index>
+          <system-if-index>2</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>9000</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T08:00:32.1Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>1</card>
+              <fp-number>1</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>174521</out-packets>
+              <out-octets>14224224</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>172336</in-packets>
+              <in-octets>14081274</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>2014</out-packets>
+              <out-octets>1703454</out-octets>
+              <in-packets>1788</in-packets>
+              <in-octets>1242133</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>1</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>1</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>153219</out-packets>
+              <out-octets>11793614</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.90</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv4-address>62.40.119.91</ipv4-address>
+                <oper-state>up</oper-state>
+                <mac-address>9c:e0:41:60:f9:2a</mac-address>
+                <type>dynamic</type>
+                <timer>3715</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>30</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>14</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>16</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>32</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>18</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>14</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <link-local-address>
+              <oper-address>fe80::1ac3:ff:fe91:fe5a</oper-address>
+              <address-state>preferred</address-state>
+            </link-local-address>
+            <statistics>
+              <out-packets>21302</out-packets>
+              <out-octets>2430610</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab:2::41</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab:2::41</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+          </ipv6>
+        </interface>
+      </router>
+      <router>
+        <router-name>management</router-name>
+        <interface>
+          <interface-name>management</interface-name>
+          <if-index>1280</if-index>
+          <system-if-index>32768</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol/>
+          <oper-ip-mtu>1500</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T07:53:27.0Z</last-oper-change>
+          <statistics>
+            <ip>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>7379</in-packets>
+              <in-octets>472036</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <primary>
+              <oper-address>172.16.254.30</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+          </ipv4>
+          <ipv6>
+            <oper-state>down</oper-state>
+            <down-reason>protocol-down</down-reason>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>0</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>0</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>0</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>0</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>0</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>0</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+          </ipv6>
+        </interface>
+      </router>
+    </state>
+  </data>
+</rpc-reply>
diff --git a/test/interface_stats/data/rt0.lon.uk.lab.office.geant.net-router-interfaces.xml b/test/interface_stats/data/rt0.lon.uk.lab.office.geant.net-router-interfaces.xml
new file mode 100644
index 0000000000000000000000000000000000000000..de697cb3e214c70ac8a97848febcf5d0ffcf946a
--- /dev/null
+++ b/test/interface_stats/data/rt0.lon.uk.lab.office.geant.net-router-interfaces.xml
@@ -0,0 +1,1028 @@
+<rpc-reply message-id="urn:uuid:726313e0-3658-472f-8ad1-6f9f287e65cd">
+  <data>
+    <state>
+      <router>
+        <router-name>Base</router-name>
+        <interface>
+          <interface-name>system</interface-name>
+          <if-index>1</if-index>
+          <system-if-index>256</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>1500</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T09:57:28.3Z</last-oper-change>
+          <statistics>
+            <ip>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.7</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>0</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>0</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>0</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>0</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>0</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>0</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab::7</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab::7</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>lag-1.0</interface-name>
+          <if-index>2</if-index>
+          <system-if-index>2</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>9000</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T09:57:28.3Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>1</card>
+              <fp-number>1</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>17459420</out-packets>
+              <out-octets>3407393702</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>2958598</in-packets>
+              <in-octets>335785704</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>2045</out-packets>
+              <out-octets>1700296</out-octets>
+              <in-packets>1616</in-packets>
+              <in-octets>1249297</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>52904</icmp-in-msgs>
+                <icmp-in-errors>46694</icmp-in-errors>
+                <icmp-in-dest-unreachables>46694</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>6210</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>6211</icmp-out-msgs>
+                <icmp-out-errors>1</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>6210</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>1</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>16615399</out-packets>
+              <out-octets>3300321263</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.86</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv4-address>62.40.119.87</ipv4-address>
+                <oper-state>up</oper-state>
+                <mac-address>ae:4b:c8:46:29:72</mac-address>
+                <type>dynamic</type>
+                <timer>13163</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>17788</icmp6-in-msgs>
+                <icmp6-in-errors>166</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>166</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>1848</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>15774</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>17622</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>15774</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>1848</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <link-local-address>
+              <oper-address>fe80::9ee0:41ff:fe60:f929</oper-address>
+              <address-state>preferred</address-state>
+            </link-local-address>
+            <statistics>
+              <out-packets>844021</out-packets>
+              <out-octets>107072439</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab:2::3d</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab:2::3d</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv6-address>fe80::ae4b:c8ff:fe46:2972</ipv6-address>
+                <state>reachable</state>
+                <is-router>true</is-router>
+                <mtu>9000</mtu>
+                <mac-address>ae:4b:c8:46:29:72</mac-address>
+                <type>dynamic</type>
+                <timer>13</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>lag-2.0</interface-name>
+          <if-index>3</if-index>
+          <system-if-index>3</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>9000</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T09:57:28.3Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>1</card>
+              <fp-number>1</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>186418</out-packets>
+              <out-octets>17279891</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>171833</in-packets>
+              <in-octets>13246928</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>1788</out-packets>
+              <out-octets>1242133</out-octets>
+              <in-packets>2014</in-packets>
+              <in-octets>1703454</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>10</icmp-in-msgs>
+                <icmp-in-errors>10</icmp-in-errors>
+                <icmp-in-dest-unreachables>10</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>164711</out-packets>
+              <out-octets>14799044</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.91</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv4-address>62.40.119.90</ipv4-address>
+                <oper-state>up</oper-state>
+                <mac-address>18:c3:00:91:fe:5a</mac-address>
+                <type>dynamic</type>
+                <timer>2976</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>28</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>15</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>13</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>28</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>13</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>15</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <link-local-address>
+              <oper-address>fe80::9ee0:41ff:fe60:f92a</oper-address>
+              <address-state>preferred</address-state>
+            </link-local-address>
+            <statistics>
+              <out-packets>21707</out-packets>
+              <out-octets>2480847</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab:2::42</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab:2::42</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>lag-3.0</interface-name>
+          <if-index>4</if-index>
+          <system-if-index>4</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol>isis mpls rsvp pim</protocol>
+          <oper-ip-mtu>9000</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T09:57:28.3Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>2</card>
+              <fp-number>1</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>373018</out-packets>
+              <out-octets>27092765</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>362600</in-packets>
+              <in-octets>30254556</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <in-packets>228</in-packets>
+              <in-octets>35044</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>350593</out-packets>
+              <out-octets>24561192</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>62.40.119.84</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv4-address>62.40.119.85</ipv4-address>
+                <oper-state>up</oper-state>
+                <mac-address>ae:4b:c8:46:29:98</mac-address>
+                <type>dynamic</type>
+                <timer>13206</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv4>
+          <ipv6>
+            <oper-state>up</oper-state>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>1000</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>501</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>499</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>1000</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>499</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>501</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <link-local-address>
+              <oper-address>fe80::9ee0:41ff:fe60:f92b</oper-address>
+              <address-state>preferred</address-state>
+            </link-local-address>
+            <statistics>
+              <out-packets>22425</out-packets>
+              <out-octets>2531573</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+            <address>
+              <ipv6-address>2001:799:1ab:2::45</ipv6-address>
+              <address-state>preferred</address-state>
+              <oper-address>2001:799:1ab:2::45</oper-address>
+              <creation-origin>manual</creation-origin>
+              <primary-preferred>true</primary-preferred>
+            </address>
+            <neighbor-discovery>
+              <neighbor>
+                <ipv6-address>fe80::ae4b:c8ff:fe46:2998</ipv6-address>
+                <state>stale</state>
+                <is-router>true</is-router>
+                <mtu>9000</mtu>
+                <mac-address>ae:4b:c8:46:29:98</mac-address>
+                <type>dynamic</type>
+                <timer>13879</timer>
+              </neighbor>
+            </neighbor-discovery>
+          </ipv6>
+        </interface>
+        <interface>
+          <interface-name>guy</interface-name>
+          <if-index>6</if-index>
+          <system-if-index>1</system-if-index>
+          <oper-state>lower-layer-down</oper-state>
+          <protocol/>
+          <oper-ip-mtu>1500</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T04:49:43.2Z</last-oper-change>
+          <distributed-cpu-protection>
+            <static-policer>
+              <name>ICMP_LIMIT</name>
+              <card>1</card>
+              <fp-number>2</fp-number>
+              <state>conform</state>
+              <exceed-count>0</exceed-count>
+              <hold-down-remain>none</hold-down-remain>
+              <detection-time-remain>0</detection-time-remain>
+              <total-exceed-count>0</total-exceed-count>
+              <exit-conform-state-count>0</exit-conform-state-count>
+            </static-policer>
+          </distributed-cpu-protection>
+          <statistics>
+            <ip>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+            <mpls>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+            </mpls>
+          </statistics>
+          <ipv4>
+            <oper-state>down</oper-state>
+            <down-reason>port-down</down-reason>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <dhcp>
+              <statistics>
+                <total-rx-packets>
+                  <received>0</received>
+                  <malformed>0</malformed>
+                  <untrusted>0</untrusted>
+                </total-rx-packets>
+                <total-tx-packets>
+                  <transmitted>0</transmitted>
+                </total-tx-packets>
+                <client-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </client-packets>
+                <server-packets>
+                  <dropped>0</dropped>
+                  <relayed>0</relayed>
+                  <snooped>0</snooped>
+                </server-packets>
+              </statistics>
+            </dhcp>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+              <out-discard-dbcast-packets>0</out-discard-dbcast-packets>
+              <out-discard-dbcast-octets>0</out-discard-dbcast-octets>
+              <in-ip-helper-redirects-packets>0</in-ip-helper-redirects-packets>
+              <in-ip-helper-redirects-octets>0</in-ip-helper-redirects-octets>
+            </statistics>
+            <primary>
+              <oper-address>10.211.101.1</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+          </ipv4>
+          <ipv6>
+            <oper-state>down</oper-state>
+            <down-reason>protocol-down</down-reason>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>0</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>0</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>0</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>0</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>0</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>0</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+            <statistics>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>0</in-packets>
+              <in-octets>0</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </statistics>
+          </ipv6>
+        </interface>
+      </router>
+      <router>
+        <router-name>management</router-name>
+        <interface>
+          <interface-name>management</interface-name>
+          <if-index>1280</if-index>
+          <system-if-index>32768</system-if-index>
+          <oper-state>up</oper-state>
+          <protocol/>
+          <oper-ip-mtu>1500</oper-ip-mtu>
+          <creation-origin>manual</creation-origin>
+          <last-oper-change>2024-04-04T12:54:59.1Z</last-oper-change>
+          <statistics>
+            <ip>
+              <out-packets>0</out-packets>
+              <out-octets>0</out-octets>
+              <out-discard-packets>0</out-discard-packets>
+              <out-discard-octets>0</out-discard-octets>
+              <in-packets>7475</in-packets>
+              <in-octets>493198</in-octets>
+              <urpf-check-fail-packets>0</urpf-check-fail-packets>
+              <urpf-check-fail-octets>0</urpf-check-fail-octets>
+            </ip>
+          </statistics>
+          <ipv4>
+            <oper-state>up</oper-state>
+            <icmp>
+              <statistics>
+                <icmp-in-msgs>0</icmp-in-msgs>
+                <icmp-in-errors>0</icmp-in-errors>
+                <icmp-in-dest-unreachables>0</icmp-in-dest-unreachables>
+                <icmp-in-redirects>0</icmp-in-redirects>
+                <icmp-in-echos>0</icmp-in-echos>
+                <icmp-in-echo-replies>0</icmp-in-echo-replies>
+                <icmp-in-time-exceeds>0</icmp-in-time-exceeds>
+                <icmp-in-src-quenches>0</icmp-in-src-quenches>
+                <icmp-in-timestamps>0</icmp-in-timestamps>
+                <icmp-in-timestamp-replies>0</icmp-in-timestamp-replies>
+                <icmp-in-address-masks>0</icmp-in-address-masks>
+                <icmp-in-address-mask-replies>0</icmp-in-address-mask-replies>
+                <icmp-in-parm-problems>0</icmp-in-parm-problems>
+                <icmp-out-msgs>0</icmp-out-msgs>
+                <icmp-out-errors>0</icmp-out-errors>
+                <icmp-out-dest-unreachables>0</icmp-out-dest-unreachables>
+                <icmp-out-redirects>0</icmp-out-redirects>
+                <icmp-out-echos>0</icmp-out-echos>
+                <icmp-out-echo-replies>0</icmp-out-echo-replies>
+                <icmp-out-time-exceeds>0</icmp-out-time-exceeds>
+                <icmp-out-src-quenches>0</icmp-out-src-quenches>
+                <icmp-out-timestamps>0</icmp-out-timestamps>
+                <icmp-out-timestamp-replies>0</icmp-out-timestamp-replies>
+                <icmp-out-address-masks>0</icmp-out-address-masks>
+                <icmp-out-address-mask-replies>0</icmp-out-address-mask-replies>
+                <icmp-out-parm-problems>0</icmp-out-parm-problems>
+                <icmp-out-discards>0</icmp-out-discards>
+              </statistics>
+            </icmp>
+            <primary>
+              <oper-address>172.16.254.32</oper-address>
+              <creation-origin>manual</creation-origin>
+            </primary>
+          </ipv4>
+          <ipv6>
+            <oper-state>down</oper-state>
+            <down-reason>protocol-down</down-reason>
+            <icmp6>
+              <statistics>
+                <icmp6-in-msgs>0</icmp6-in-msgs>
+                <icmp6-in-errors>0</icmp6-in-errors>
+                <icmp6-in-dest-unreachables>0</icmp6-in-dest-unreachables>
+                <icmp6-in-admin-prohibs>0</icmp6-in-admin-prohibs>
+                <icmp6-in-time-exceeds>0</icmp6-in-time-exceeds>
+                <icmp6-in-parm-problems>0</icmp6-in-parm-problems>
+                <icmp6-in-pkt-too-bigs>0</icmp6-in-pkt-too-bigs>
+                <icmp6-in-echos>0</icmp6-in-echos>
+                <icmp6-in-echo-replies>0</icmp6-in-echo-replies>
+                <icmp6-in-rtr-solicits>0</icmp6-in-rtr-solicits>
+                <icmp6-in-rtr-advertisements>0</icmp6-in-rtr-advertisements>
+                <icmp6-in-nbr-solicits>0</icmp6-in-nbr-solicits>
+                <icmp6-in-nbr-advertisements>0</icmp6-in-nbr-advertisements>
+                <icmp6-in-redirects>0</icmp6-in-redirects>
+                <icmp6-in-grp-memb-queries>0</icmp6-in-grp-memb-queries>
+                <icmp6-in-grp-memb-repsonses>0</icmp6-in-grp-memb-repsonses>
+                <icmp6-in-grp-memb-reductions>0</icmp6-in-grp-memb-reductions>
+                <icmp6-out-msgs>0</icmp6-out-msgs>
+                <icmp6-out-errors>0</icmp6-out-errors>
+                <icmp6-out-dest-unreachables>0</icmp6-out-dest-unreachables>
+                <icmp6-out-admin-prohibs>0</icmp6-out-admin-prohibs>
+                <icmp6-out-time-exceeds>0</icmp6-out-time-exceeds>
+                <icmp6-out-parm-problems>0</icmp6-out-parm-problems>
+                <icmp6-out-pkt-too-bigs>0</icmp6-out-pkt-too-bigs>
+                <icmp6-out-echos>0</icmp6-out-echos>
+                <icmp6-out-echo-replies>0</icmp6-out-echo-replies>
+                <icmp6-out-rtr-solicits>0</icmp6-out-rtr-solicits>
+                <icmp6-out-rtr-advertisements>0</icmp6-out-rtr-advertisements>
+                <icmp6-out-nbr-solicits>0</icmp6-out-nbr-solicits>
+                <icmp6-out-nbr-advertisements>0</icmp6-out-nbr-advertisements>
+                <icmp6-out-redirects>0</icmp6-out-redirects>
+                <icmp6-out-grp-memb-queries>0</icmp6-out-grp-memb-queries>
+                <icmp6-out-grp-memb-responses>0</icmp6-out-grp-memb-responses>
+                <icmp6-out-grp-memb-reductions>0</icmp6-out-grp-memb-reductions>
+                <icmp6-out-discards>0</icmp6-out-discards>
+              </statistics>
+            </icmp6>
+          </ipv6>
+        </interface>
+      </router>
+    </state>
+  </data>
+</rpc-reply>
diff --git a/test/interface_stats/test_interface_stats.py b/test/interface_stats/test_interface_stats.py
index bb620af89de628eb483032171a0af2e89a897db0..d87cfc2c7fed7fba65fafccaa2bf6735241148f0 100644
--- a/test/interface_stats/test_interface_stats.py
+++ b/test/interface_stats/test_interface_stats.py
@@ -1,5 +1,3 @@
-import itertools
-import re
 from datetime import datetime
 from unittest.mock import Mock, call, patch
 
@@ -7,12 +5,12 @@ from brian_polling_manager import influx
 import jsonschema
 import pytest
 from brian_polling_manager.interface_stats import cli
-from brian_polling_manager.interface_stats.vendors import Vendor, common, juniper, nokia
+from brian_polling_manager.interface_stats.vendors import Vendor, common
 from lxml import etree
-from ncclient.operations.rpc import RPCReply
+import ncclient.manager
 
 
-def test_sanity_check_snapshot_data(polled_interfaces, all_juniper_routers):
+def test_sanity_check_juniper_snapshot_data(polled_interfaces, all_juniper_routers):
     """
     verify that all routers with interfaces to be polled
     are in the test data set
@@ -22,37 +20,12 @@ def test_sanity_check_snapshot_data(polled_interfaces, all_juniper_routers):
     assert len(missing_routers) == 0
 
 
-def test_verify_all_interfaces_present(juniper_router_fqdn, polled_interfaces):
-    """
-    verify that all the interfaces we expect to poll
-    are available in the netconf data
-    compares a snapshot of all netconf docs with a
-    a snapshot of inventory /poller/interfaces
-    (the snapshots were all taken around the same time)
-    """
-
-    def _is_enabled(ifc_name, ifc_doc):
-        m = re.match(r"^([^\.]+)\.?.*", ifc_name)
-        assert m  # sanity: should never fail
-        phy = ifc_doc.xpath(
-            f'//interface-information/physical-interface[normalize-space(name)="{m.group(1)}"]'
-        )[0]
-        admin_status = phy.xpath("./admin-status/text()")[0].strip()
-        oper_status = phy.xpath("./oper-status/text()")[0].strip()
-
-        return admin_status == "up" and oper_status == "up"
-
-    if juniper_router_fqdn not in polled_interfaces:
-        pytest.skip(f"{juniper_router_fqdn} has no expected polled interfaces")
-
-    doc = cli.get_netconf(juniper_router_fqdn, vendor=Vendor.JUNIPER, ssh_params={})
-    phy = juniper._physical_interface_counters(doc)
-    log = juniper._logical_interface_counters(doc)
-    interfaces = set(x["name"] for x in itertools.chain(phy, log))
-    missing_interfaces = polled_interfaces[juniper_router_fqdn] - interfaces
-    for ifc_name in missing_interfaces:
-        # verify that any missing interfaces are admin/oper disabled
-        assert not _is_enabled(ifc_name, doc)
+def test_sanity_check_nokia_snapshot_data(all_nokia_routers):
+    # TODO: update this once we have Nokia routers in inventory provider
+    assert set(all_nokia_routers) == {
+        "rt0.ams.nl.lab.office.geant.net",
+        "rt0.lon.uk.lab.office.geant.net",
+    }
 
 
 class TestParseCounters:
@@ -106,199 +79,6 @@ class TestParseCounters:
         assert "found more than one ./a" in record.message
 
 
-@pytest.fixture
-def juniper_router_doc_containing_every_field():
-    doc = """\
-<interface-information>
-    <physical-interface>
-        <name>ae12</name>
-        <admin-status>up</admin-status>
-        <oper-status>up</oper-status>
-        <traffic-statistics>
-            <input-bytes>1</input-bytes>
-            <input-packets>2</input-packets>
-            <output-bytes>3</output-bytes>
-            <output-packets>4</output-packets>
-            <ipv6-transit-statistics>
-                <input-bytes>5</input-bytes>
-                <input-packets>6</input-packets>
-                <output-bytes>7</output-bytes>
-                <output-packets>8</output-packets>
-            </ipv6-transit-statistics>
-        </traffic-statistics>
-        <input-error-list>
-            <input-errors>11</input-errors>
-            <input-discards>12</input-discards>
-            <input-fifo-errors>13</input-fifo-errors>
-            <input-drops>14</input-drops>
-            <framing-errors>15</framing-errors>
-            <input-resource-errors>16</input-resource-errors>
-        </input-error-list>
-        <output-error-list>
-            <output-errors>21</output-errors>
-            <output-drops>22</output-drops>
-            <output-resource-errors>23</output-resource-errors>
-            <output-fifo-errors>24</output-fifo-errors>
-            <output-collisions>25</output-collisions>
-        </output-error-list>
-        <ethernet-mac-statistics>
-            <input-crc-errors>31</input-crc-errors>
-            <output-crc-errors>32</output-crc-errors>
-            <input-total-errors>33</input-total-errors>
-            <output-total-errors>34</output-total-errors>
-        </ethernet-mac-statistics>
-        <ethernet-pcs-statistics>
-            <bit-error-seconds>41</bit-error-seconds>
-            <errored-blocks-seconds>42</errored-blocks-seconds>
-        </ethernet-pcs-statistics>
-        <logical-interface>
-            <name>ae12.1</name>
-            <traffic-statistics>
-                <input-bytes>51</input-bytes>
-                <input-packets>52</input-packets>
-                <output-bytes>53</output-bytes>
-                <output-packets>54</output-packets>
-                <ipv6-transit-statistics>
-                    <input-bytes>55</input-bytes>
-                    <input-packets>56</input-packets>
-                    <output-bytes>57</output-bytes>
-                    <output-packets>58</output-packets>
-                </ipv6-transit-statistics>
-            </traffic-statistics>
-        </logical-interface>
-    </physical-interface>
-</interface-information>
-"""
-    return etree.fromstring(doc)
-
-
-def test_physical_interface_counters(juniper_router_doc_containing_every_field):
-    result = list(
-        juniper._physical_interface_counters(juniper_router_doc_containing_every_field)
-    )
-    assert len(result) == 1
-    assert result[0] == {
-        "name": "ae12",
-        "brian": {
-            "ingressOctets": 1,
-            "ingressPackets": 2,
-            "egressOctets": 3,
-            "egressPackets": 4,
-            "ingressOctetsv6": 5,
-            "ingressPacketsv6": 6,
-            "egressOctetsv6": 7,
-            "egressPacketsv6": 8,
-            "ingressErrors": 11,
-            "ingressDiscards": 12,
-            "egressErrors": 21,
-        },
-        "errors": {
-            "input_discards": 12,
-            "input_fifo_errors": 13,
-            "input_drops": 14,
-            "input_framing_errors": 15,
-            "input_resource_errors": 16,
-            "output_drops": 22,
-            "output_resource_errors": 23,
-            "output_fifo_errors": 24,
-            "output_collisions": 25,
-            "input_crc_errors": 31,
-            "output_crc_errors": 32,
-            "input_total_errors": 33,
-            "output_total_errors": 34,
-            "bit_error_seconds": 41,
-            "errored_blocks_seconds": 42,
-        },
-    }
-
-
-def test_logical_interface_counters(juniper_router_doc_containing_every_field):
-    result = list(
-        juniper._logical_interface_counters(juniper_router_doc_containing_every_field)
-    )
-    assert len(result) == 1
-    assert result[0] == {
-        "name": "ae12.1",
-        "brian": {
-            "ingressOctets": 51,
-            "ingressPackets": 52,
-            "egressOctets": 53,
-            "egressPackets": 54,
-            "ingressOctetsv6": 55,
-            "ingressPacketsv6": 56,
-            "egressOctetsv6": 57,
-            "egressPacketsv6": 58,
-        },
-    }
-
-
-def test_juniper_router_docs_do_not_generate_errors(juniper_router_fqdn, caplog):
-    doc = cli.get_netconf(juniper_router_fqdn, ssh_params=None, vendor=Vendor.JUNIPER)
-    counters = list(juniper.interface_counters(doc))
-    assert counters
-    assert not [r for r in caplog.records if r.levelname in ("ERROR", "WARNING")]
-
-
-def test_nokia_router_docs_do_not_generate_errors(nokia_router_fqdn, caplog):
-    doc = cli.get_netconf(nokia_router_fqdn, ssh_params=None, vendor=Vendor.NOKIA)
-    counters = list(nokia.interface_counters(doc))
-    assert counters
-    assert not [r for r in caplog.records if r.levelname in ("ERROR", "WARNING")]
-
-
-def test_validate_interface_schema_for_all_juniper_routers(
-    juniper_router_fqdn, data_dir
-):
-    doc = juniper.get_netconf_interface_info_from_source_dir(
-        juniper_router_fqdn, data_dir
-    )
-    interfaces = list(juniper._physical_interface_counters(doc))
-    assert interfaces
-    for ifc in interfaces:
-        jsonschema.validate(ifc, common.PHYSICAL_INTERFACE_COUNTER_SCHEMA)
-
-    interfaces = list(juniper._logical_interface_counters(doc))
-    assert interfaces
-    for ifc in interfaces:
-        jsonschema.validate(ifc, common.LOGICAL_INTERFACE_COUNTER_SCHEMA)
-
-
-def test_validate_generate_points_for_all_juniper_routers(
-    juniper_router_fqdn, data_dir
-):
-    doc = juniper.get_netconf_interface_info_from_source_dir(
-        juniper_router_fqdn, data_dir
-    )
-    interfaces = list(juniper.interface_counters(doc))
-    assert interfaces
-
-    bpoints = list(
-        common.brian_points(
-            juniper_router_fqdn,
-            interfaces,
-            timestamp=datetime.now(),
-            measurement_name="blah",
-        )
-    )
-    assert bpoints
-    for point in bpoints:
-        jsonschema.validate(point, influx.INFLUX_POINT)
-        jsonschema.validate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA)
-
-    epoints = list(
-        common.error_points(
-            juniper_router_fqdn,
-            interfaces,
-            timestamp=datetime.now(),
-            measurement_name="blah",
-        )
-    )
-    assert epoints
-    for point in epoints:
-        jsonschema.validate(point, influx.INFLUX_POINT)
-        jsonschema.validate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA)
-
-
 def test_brian_point_counters():
     now = datetime.now()
     points = list(
@@ -379,7 +159,9 @@ def test_no_error_point_counters():
 
 
 @patch.object(cli, "write_points")
-def test_main_for_all_juniper_routers(write_points, all_juniper_routers):
+def test_main_for_all_juniper_routers(
+    write_points, mocked_get_netconf, all_juniper_routers
+):
     config = {
         "juniper": {"some": "params"},
         "influx": {
@@ -413,40 +195,6 @@ def test_main_for_all_juniper_routers(write_points, all_juniper_routers):
     assert total_points > 0
 
 
-class TestGetJuniperNetConf:
-    RAW_RESPONSE_FILE = "raw-response-sample.xml"
-
-    @pytest.fixture(autouse=True)
-    def mocked_rpc(self, data_dir):
-        raw_response = data_dir.joinpath(self.RAW_RESPONSE_FILE).read_text()
-        with patch.object(juniper, "_rpc", return_value=RPCReply(raw_response)) as mock:
-            yield mock
-
-    @pytest.fixture(autouse=True)
-    def unmock_get_netconf(self, mocked_juniper_get_netconf_interface_info):
-        mocked_juniper_get_netconf_interface_info.stop()
-
-    def test_calls_rpc_with_params(self, mocked_rpc):
-        router_name = "some-router"
-        cli.get_netconf(
-            router_name, vendor=Vendor.JUNIPER, ssh_params={"some": "param"}
-        )
-
-        call_args = mocked_rpc.call_args
-        assert call_args[0][0] == router_name
-        assert call_args[1]["ssh_params"] == {"some": "param"}
-        assert call_args[1]["command"].tag == "get-interface-information"
-
-    def test_converts_rpc_response_to_xml(self):
-        router_name = "some-router"
-
-        doc = cli.get_netconf(
-            router_name, vendor=Vendor.JUNIPER, ssh_params={"some": "param"}
-        )
-
-        assert doc.tag == "rpc-reply"
-
-
 @pytest.fixture
 def load_interfaces():
     return Mock(
@@ -515,17 +263,13 @@ def test_write_points_to_stdout():
     ]
 
 
-@pytest.mark.parametrize(
-    "hostname", ["rt0.lon.uk.lab.office.geant.net", "rt0.ams.nl.lab.office.geant.net"]
-)
-def test_nokia_counters(hostname):
-    """
-    quick poc
-    :return:
-    """
-    doc = cli.get_netconf(hostname, vendor=Vendor.NOKIA, ssh_params={})
-    counters = list(nokia.interface_counters(doc))
-    assert counters
-    for counter in counters:
-        jsonschema.validate(counter, common.NOKIA_INTERFACE_COUNTER_SCHEMA)
-    print(len(counters))
+@patch.object(ncclient.manager, "connect")
+def test_netconf_connect(connect):
+    with common.netconf_connect(
+        hostname="some.router", ssh_params={"ssh": "param"}, other="more_params"
+    ):
+        pass
+
+    assert connect.call_args == call(
+        host="some.router", ssh="param", other="more_params", port=830
+    )
diff --git a/test/interface_stats/test_interface_stats_e2e.py b/test/interface_stats/test_interface_stats_e2e.py
index fa82c5ad0309d3b2498eb85e75f427796a3e8930..26c526f5ff2a3563cbb9a4dd8a0d7f36b3757f72 100644
--- a/test/interface_stats/test_interface_stats_e2e.py
+++ b/test/interface_stats/test_interface_stats_e2e.py
@@ -11,7 +11,7 @@ from unittest.mock import patch
 from brian_polling_manager.influx import influx_client
 from brian_polling_manager.interface_stats.vendors import common
 from click.testing import CliRunner
-from typing import Any, Dict
+from typing import Any, Dict, Optional, Set
 from brian_polling_manager.interface_stats import cli
 import concurrent.futures
 import pytest
@@ -31,10 +31,29 @@ def free_host_port():
 
 
 @pytest.fixture
-def testenv_containers(testenv_compose_params: Dict[str, Any]):
+def influx_params(free_host_port):
+    return {
+        "hostname": "localhost",
+        "port": free_host_port,
+        "database": "testdb",
+        "username": "bogus-user",
+        "password": "bogus-password",
+        "ssl": False,
+    }
+
+
+@pytest.fixture
+def influx_container(influx_compose_params: Dict[str, Any]):
+    # PK: we may want to make this a session scoped fixture to reduce test setup time.
+    # However, we then have to make sure to clean up the database after every test
+    # and I couldn't quickly get the admin user properly authorized to do this (which is
+    # weird). Together with the fact that we only have two tests running against a
+    # container and the expected speed-up is limited, I decided to let this fixture be
+    # function scoped for now
+
     with run_compose(
-        compose_filename=testenv_compose_params["compose_filename"],
-        container_names=[testenv_compose_params["container"]],
+        compose_filename=influx_compose_params["compose_filename"],
+        container_names=[influx_compose_params["container"]],
     ):
         # wait here until the caller context finishes
         yield
@@ -66,50 +85,32 @@ def app_config_filename(app_config_params: Dict[str, Any]):
 
 
 @pytest.fixture
-def brian_influx_container_params(app_config_params: Dict[str, Any]):
-
+def brian_influx_container_params(influx_params: Dict[str, Any]):
     container_name = f"brian-influxdb-{random.randint(1000, 10000)}"
-
-    # sanity (using same container for both)
-    assert (
-        app_config_params["influx"]["brian-counters"]["port"]
-        == app_config_params["influx"]["error-counters"]["port"]
-    )
-    assert (
-        app_config_params["influx"]["brian-counters"]["hostname"]
-        == app_config_params["influx"]["error-counters"]["hostname"]
-    )
-
-    influx_params = app_config_params["influx"]["brian-counters"]
-
-    with tempfile.TemporaryDirectory() as influx_data_dirname:
-        os.chmod(influx_data_dirname, 0o777)
-        yield {
-            "image": "bitnami/influxdb:1.8.5-debian-10-r197",
-            "user": f"{os.getuid()}",
-            "container_name": container_name,
-            # this image serves on 2222
-            "ports": [f'{influx_params["port"]}:8086'],
-            "environment": {
-                "INFLUXDB_HTTP_AUTH_ENABLED": "true",
-                "INFLUXDB_ADMIN_USER": "admin123",
-                "INFLUXDB_ADMIN_USER_PASSWORD": "secret",
-                "INFLUXDB_USER": influx_params["username"],
-                "INFLUXDB_USER_PASSWORD": influx_params["password"],
-                "INFLUXDB_DB": influx_params["database"],  # no dashes!!
-                "INFLUXDB_LOGGING_LEVEL": "debug",
-            },
-            "healthcheck": {
-                "interval": "2s",
-                "timeout": "2s",
-                "retries": 2,
-                "test": ["CMD", "curl", "-f", "http://localhost:8086/ping"],
-            },
-        }
+    return {
+        "image": "bitnami/influxdb:1.8.5-debian-10-r197",
+        "container_name": container_name,
+        "ports": [f'{influx_params["port"]}:8086'],
+        "environment": {
+            "INFLUXDB_HTTP_AUTH_ENABLED": "true",
+            "INFLUXDB_ADMIN_USER": "admin123",
+            "INFLUXDB_ADMIN_USER_PASSWORD": "secret",
+            "INFLUXDB_USER": influx_params["username"],
+            "INFLUXDB_USER_PASSWORD": influx_params["password"],
+            "INFLUXDB_DB": influx_params["database"],  # no dashes!!
+            "INFLUXDB_LOGGING_LEVEL": "debug",
+        },
+        "healthcheck": {
+            "interval": "2s",
+            "timeout": "2s",
+            "retries": 2,
+            "test": ["CMD", "curl", "-f", "http://localhost:8086/ping"],
+        },
+    }
 
 
 @pytest.fixture
-def testenv_compose_params(brian_influx_container_params: Dict[str, Any]):
+def influx_compose_params(brian_influx_container_params: Dict[str, Any]):
     compose_config = {
         "version": "3.8",
         "services": {
@@ -212,12 +213,7 @@ def test_config_file_validation(app_config_filename: str):
 
 
 @pytest.fixture
-def app_config_params(free_host_port, data_dir):
-
-    testenv_dbname = "testdb"  # can't contain dashes
-    testenv_username = "bogus-user"
-    testenv_password = "bogus-password"
-
+def app_config_params(influx_params):
     with tempfile.NamedTemporaryFile() as f:
         yield {
             "juniper": {
@@ -238,31 +234,18 @@ def app_config_params(free_host_port, data_dir):
             },
             "influx": {
                 "brian-counters": {
-                    "hostname": "localhost",
-                    "port": free_host_port,
-                    "database": testenv_dbname,
+                    **influx_params,
                     "measurement": "testenv_brian_counters",
-                    "username": testenv_username,
-                    "password": testenv_password,
-                    "ssl": False,
                 },
                 "error-counters": {
-                    "hostname": "localhost",
-                    "port": free_host_port,
-                    "database": testenv_dbname,
+                    **influx_params,
                     "measurement": "testenv_error_counters",
-                    "username": testenv_username,
-                    "password": testenv_password,
-                    "ssl": False,
                 },
             },
         }
 
 
-@pytest.mark.parametrize(
-    "output",
-    iter(cli.OutputMethod),
-)
+@pytest.mark.parametrize("output", iter(cli.OutputMethod))
 @patch.object(cli, "setup_logging")
 @patch.object(cli, "main", return_value=0)
 def test_cli_output_option(
@@ -282,15 +265,65 @@ def test_cli_output_option(
     assert main.call_args[1]["output"] == output
 
 
+def verify_influx_content(
+    influx_config: dict,
+    schema: dict,
+    only: Optional[Set[str]] = None,
+    exclude: Optional[Set[str]] = None,
+):
+    """For each field in the ``schema``, verify there is at least one point with that
+    field populated in influx.
+
+    :param influx_config: an influx config with connection info and a ``measurement``
+        key
+    :param schema: either common.ERROR_POINT_FIELDS_SCHEMA or
+        common.BRIAN_POINT_FIELDS_SCHEMA
+    :param only: Optional. Only test for a subset of the keys in the schema. Do not use
+        together with ``exclude``
+    :param exclude: Optional. Exclude a subset from the keys in the schema to test for.
+        Do not use together with ``only``
+    """
+    # for each expected field, verify that there's
+    # at least one point with that field populated
+
+    assert (
+        schema is common.ERROR_POINT_FIELDS_SCHEMA
+        or schema is common.BRIAN_POINT_FIELDS_SCHEMA
+    )
+    expected_fields = schema["properties"].keys()
+
+    if only is not None and exclude is not None:
+        raise ValueError("do not supply both 'only' and 'exclude' argument")
+
+    if only is not None:
+        assert only.issubset(expected_fields)
+        expected_fields = only
+    elif exclude is not None:
+        assert exclude.issubset(expected_fields)
+        expected_fields -= exclude
+
+    with contextlib.closing(influx_client(influx_config)) as client:
+        query = f'select count(*) from {influx_config["measurement"]}'
+        counts = next(
+            client.query(query).get_points(measurement=influx_config["measurement"])
+        )
+
+        expected_count_fields = {f"count_{n}" for n in expected_fields}
+
+        assert expected_count_fields == set(counts.keys()) - {"time"}
+        assert all(counts[_f] > 0 for _f in expected_count_fields)
+
+
 @pytest.mark.skipif(
     not _use_docker_compose(), reason="docker compose not found or disabled"
 )
 @patch.object(cli, "setup_logging")
-def test_e2e(
+def test_e2e_juniper(
     unused_setup_logging,
+    mocked_get_netconf,
     app_config_params: Dict[str, Any],
     app_config_filename: str,
-    testenv_containers: None,
+    influx_container: None,
     all_juniper_routers,
 ):
     """
@@ -308,34 +341,57 @@ def test_e2e(
     result = runner.invoke(cli.cli, cli_args)
     assert result.exit_code == 0, str(result)
 
-    def verify_influx_content(influx_config, expected_fields):
-        # for each expected field, verify that there's
-        # at least one point with that field populated
+    verify_influx_content(
+        influx_config=app_config_params["influx"]["brian-counters"],
+        schema=common.BRIAN_POINT_FIELDS_SCHEMA,
+    )
 
-        with contextlib.closing(influx_client(influx_config)) as client:
-            query = f'select count(*) from {influx_config["measurement"]}'
-            counts = next(
-                client.query(query).get_points(measurement=influx_config["measurement"])
-            )
+    verify_influx_content(
+        influx_config=app_config_params["influx"]["error-counters"],
+        schema=common.ERROR_POINT_FIELDS_SCHEMA,
+        exclude={"output_discards"},
+    )
 
-            expected_count_fields = {f"count_{n}" for n in expected_fields}
 
-            assert expected_count_fields.issubset(counts.keys())
-            assert all(counts[_f] > 0 for _f in expected_count_fields)
+@pytest.mark.skipif(
+    not _use_docker_compose(), reason="docker compose not found or disabled"
+)
+@patch.object(cli, "setup_logging")
+def test_e2e_nokia(
+    unused_setup_logging,
+    mocked_get_netconf,
+    app_config_params: Dict[str, Any],
+    app_config_filename: str,
+    influx_container: None,
+    all_nokia_routers,
+):
+    """
+    load all router interfaces into a tmp influx container, check that
+    all potential counter fields are populated
+    """
 
-    def _expected_fields_from_schema(schema):
-        assert (
-            schema == common.ERROR_POINT_FIELDS_SCHEMA
-            or schema == common.BRIAN_POINT_FIELDS_SCHEMA
-        )
-        return schema["properties"].keys()
+    cli_args = [
+        "--config",
+        app_config_filename,
+        "--nokia",
+        *all_nokia_routers,
+    ]
+    runner = CliRunner()
+    result = runner.invoke(cli.cli, cli_args)
+    assert result.exit_code == 0, str(result)
 
     verify_influx_content(
         influx_config=app_config_params["influx"]["brian-counters"],
-        expected_fields=_expected_fields_from_schema(common.BRIAN_POINT_FIELDS_SCHEMA),
+        schema=common.BRIAN_POINT_FIELDS_SCHEMA,
     )
 
     verify_influx_content(
         influx_config=app_config_params["influx"]["error-counters"],
-        expected_fields=_expected_fields_from_schema(common.ERROR_POINT_FIELDS_SCHEMA),
+        schema=common.ERROR_POINT_FIELDS_SCHEMA,
+        only={
+            "output_total_errors",
+            "input_total_errors",
+            "input_discards",
+            "output_discards",
+        },
     )
diff --git a/test/interface_stats/test_juniper.py b/test/interface_stats/test_juniper.py
new file mode 100644
index 0000000000000000000000000000000000000000..90567e5abf9b5251a137a93b2d29449dcd74c80a
--- /dev/null
+++ b/test/interface_stats/test_juniper.py
@@ -0,0 +1,261 @@
+from datetime import datetime
+import itertools
+import re
+from unittest.mock import call, patch
+
+import jsonschema
+import pytest
+from brian_polling_manager import influx
+from brian_polling_manager.interface_stats.vendors import common, juniper
+from lxml import etree
+from ncclient.operations.rpc import RPCReply
+
+
+@pytest.fixture
+def get_netconf(data_dir):
+    def _get_netconf(router_name):
+        return juniper.get_netconf_interface_info_from_source_dir(
+            router_name, source_dir=data_dir
+        )
+
+    return _get_netconf
+
+
+@pytest.fixture
+def juniper_router_doc_containing_every_field():
+    doc = """\
+<interface-information>
+    <physical-interface>
+        <name>ae12</name>
+        <admin-status>up</admin-status>
+        <oper-status>up</oper-status>
+        <traffic-statistics>
+            <input-bytes>1</input-bytes>
+            <input-packets>2</input-packets>
+            <output-bytes>3</output-bytes>
+            <output-packets>4</output-packets>
+            <ipv6-transit-statistics>
+                <input-bytes>5</input-bytes>
+                <input-packets>6</input-packets>
+                <output-bytes>7</output-bytes>
+                <output-packets>8</output-packets>
+            </ipv6-transit-statistics>
+        </traffic-statistics>
+        <input-error-list>
+            <input-errors>11</input-errors>
+            <input-discards>12</input-discards>
+            <input-fifo-errors>13</input-fifo-errors>
+            <input-drops>14</input-drops>
+            <framing-errors>15</framing-errors>
+            <input-resource-errors>16</input-resource-errors>
+        </input-error-list>
+        <output-error-list>
+            <output-errors>21</output-errors>
+            <output-drops>22</output-drops>
+            <output-resource-errors>23</output-resource-errors>
+            <output-fifo-errors>24</output-fifo-errors>
+            <output-collisions>25</output-collisions>
+            <output-discards>26</output-discards>
+        </output-error-list>
+        <ethernet-mac-statistics>
+            <input-crc-errors>31</input-crc-errors>
+            <output-crc-errors>32</output-crc-errors>
+            <input-total-errors>33</input-total-errors>
+            <output-total-errors>34</output-total-errors>
+        </ethernet-mac-statistics>
+        <ethernet-pcs-statistics>
+            <bit-error-seconds>41</bit-error-seconds>
+            <errored-blocks-seconds>42</errored-blocks-seconds>
+        </ethernet-pcs-statistics>
+        <logical-interface>
+            <name>ae12.1</name>
+            <traffic-statistics>
+                <input-bytes>51</input-bytes>
+                <input-packets>52</input-packets>
+                <output-bytes>53</output-bytes>
+                <output-packets>54</output-packets>
+                <ipv6-transit-statistics>
+                    <input-bytes>55</input-bytes>
+                    <input-packets>56</input-packets>
+                    <output-bytes>57</output-bytes>
+                    <output-packets>58</output-packets>
+                </ipv6-transit-statistics>
+            </traffic-statistics>
+        </logical-interface>
+    </physical-interface>
+</interface-information>
+"""
+    return etree.fromstring(doc)
+
+
+def test_verify_all_interfaces_present(
+    juniper_router_fqdn, polled_interfaces, get_netconf
+):
+    """
+    verify that all the interfaces we expect to poll
+    are available in the netconf data
+    compares a snapshot of all netconf docs with a
+    a snapshot of inventory /poller/interfaces
+    (the snapshots were all taken around the same time)
+    """
+
+    def _is_enabled(ifc_name, ifc_doc):
+        m = re.match(r"^([^\.]+)\.?.*", ifc_name)
+        assert m  # sanity: should never fail
+        phy = ifc_doc.xpath(
+            f'//interface-information/physical-interface[normalize-space(name)="{m.group(1)}"]'
+        )[0]
+        admin_status = phy.xpath("./admin-status/text()")[0].strip()
+        oper_status = phy.xpath("./oper-status/text()")[0].strip()
+
+        return admin_status == "up" and oper_status == "up"
+
+    if juniper_router_fqdn not in polled_interfaces:
+        pytest.skip(f"{juniper_router_fqdn} has no expected polled interfaces")
+
+    doc = get_netconf(juniper_router_fqdn)
+    phy = juniper._physical_interface_counters(doc)
+    log = juniper._logical_interface_counters(doc)
+    interfaces = set(x["name"] for x in itertools.chain(phy, log))
+    missing_interfaces = polled_interfaces[juniper_router_fqdn] - interfaces
+    for ifc_name in missing_interfaces:
+        # verify that any missing interfaces are admin/oper disabled
+        assert not _is_enabled(ifc_name, doc)
+
+
+def test_physical_interface_counters(juniper_router_doc_containing_every_field):
+    result = list(
+        juniper._physical_interface_counters(juniper_router_doc_containing_every_field)
+    )
+    assert len(result) == 1
+    assert result[0] == {
+        "name": "ae12",
+        "brian": {
+            "ingressOctets": 1,
+            "ingressPackets": 2,
+            "egressOctets": 3,
+            "egressPackets": 4,
+            "ingressOctetsv6": 5,
+            "ingressPacketsv6": 6,
+            "egressOctetsv6": 7,
+            "egressPacketsv6": 8,
+            "ingressErrors": 11,
+            "ingressDiscards": 12,
+            "egressErrors": 21,
+        },
+        "errors": {
+            "input_discards": 12,
+            "input_fifo_errors": 13,
+            "input_drops": 14,
+            "input_framing_errors": 15,
+            "input_resource_errors": 16,
+            "output_drops": 22,
+            "output_resource_errors": 23,
+            "output_fifo_errors": 24,
+            "output_collisions": 25,
+            "output_discards": 26,
+            "input_crc_errors": 31,
+            "output_crc_errors": 32,
+            "input_total_errors": 33,
+            "output_total_errors": 34,
+            "bit_error_seconds": 41,
+            "errored_blocks_seconds": 42,
+        },
+    }
+
+
+def test_logical_interface_counters(juniper_router_doc_containing_every_field):
+    result = list(
+        juniper._logical_interface_counters(juniper_router_doc_containing_every_field)
+    )
+    assert len(result) == 1
+    assert result[0] == {
+        "name": "ae12.1",
+        "brian": {
+            "ingressOctets": 51,
+            "ingressPackets": 52,
+            "egressOctets": 53,
+            "egressPackets": 54,
+            "ingressOctetsv6": 55,
+            "ingressPacketsv6": 56,
+            "egressOctetsv6": 57,
+            "egressPacketsv6": 58,
+        },
+    }
+
+
+def test_juniper_router_docs_do_not_generate_errors(
+    get_netconf, juniper_router_fqdn, caplog
+):
+    doc = get_netconf(juniper_router_fqdn)
+    counters = list(juniper.interface_counters(doc))
+    assert counters
+    assert not [r for r in caplog.records if r.levelname in ("ERROR", "WARNING")]
+
+
+def test_validate_interface_counters_and_influx_points_for_all_juniper_routers(
+    juniper_router_fqdn, get_netconf
+):
+    doc = get_netconf(juniper_router_fqdn)
+    interfaces = list(juniper.interface_counters(doc))
+    assert interfaces
+    for ifc in interfaces:
+        jsonschema.validate(ifc, common.INTERFACE_COUNTER_SCHEMA)
+
+    bpoints = list(
+        common.brian_points(
+            juniper_router_fqdn,
+            interfaces,
+            timestamp=datetime.now(),
+            measurement_name="blah",
+        )
+    )
+    assert bpoints
+    for point in bpoints:
+        jsonschema.validate(point, influx.INFLUX_POINT)
+        jsonschema.validate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA)
+
+    epoints = list(
+        common.error_points(
+            juniper_router_fqdn,
+            interfaces,
+            timestamp=datetime.now(),
+            measurement_name="blah",
+        )
+    )
+    assert epoints
+    for point in epoints:
+        jsonschema.validate(point, influx.INFLUX_POINT)
+        jsonschema.validate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA)
+
+
+class TestGetJuniperNetConf:
+    RAW_RESPONSE_FILE = "raw-response-juniper-sample.xml"
+
+    @pytest.fixture(autouse=True)
+    def mocked_connect(self, data_dir):
+        raw_response = data_dir.joinpath(self.RAW_RESPONSE_FILE).read_text()
+        with patch.object(juniper, "netconf_connect") as mock:
+            mock().__enter__().rpc.return_value = RPCReply(raw_response)
+            mock.reset_mock()
+            yield mock
+
+    def test_calls_ncclient_with_params(self, mocked_connect):
+        router_name = "some-router"
+        juniper.get_netconf_interface_info(router_name, ssh_params={"ssh": "param"})
+
+        mocked_connect.call_args = call(hostname="some-router", ssh="param", timeout=5)
+
+        assert (
+            mocked_connect().__enter__().rpc.call_args[0][0].tag
+            == "get-interface-information"
+        )
+
+    def test_converts_rpc_response_to_xml(self):
+        router_name = "some-router"
+
+        doc = juniper.get_netconf_interface_info(
+            router_name, ssh_params={"some": "param"}
+        )
+
+        assert doc.tag == "rpc-reply"
diff --git a/test/interface_stats/test_nokia.py b/test/interface_stats/test_nokia.py
new file mode 100644
index 0000000000000000000000000000000000000000..fbe8a1f998d73fbaae4e1c44ef52466f6d6cea32
--- /dev/null
+++ b/test/interface_stats/test_nokia.py
@@ -0,0 +1,260 @@
+from datetime import datetime
+from unittest.mock import call, patch
+from brian_polling_manager import influx
+from brian_polling_manager.interface_stats.vendors import common, nokia
+import jsonschema
+import pytest
+from lxml import etree
+
+
+@pytest.fixture
+def get_netconf(data_dir):
+    def _get_netconf(router_name):
+        return nokia.get_netconf_interface_info_from_source_dir(
+            router_name, source_dir=data_dir
+        )
+
+    return _get_netconf
+
+
+NOKIA_PORT_XML = """\
+<rpc-reply>
+  <data>
+    <state>
+      <port>
+        <port-id>1/1/c1</port-id>
+        <oper-state>up</oper-state>
+        <statistics>
+          <in-octets>1</in-octets>
+          <in-packets>2</in-packets>
+          <out-octets>3</out-octets>
+          <out-packets>4</out-packets>
+          <in-errors>5</in-errors>
+          <in-discards>6</in-discards>
+          <out-errors>7</out-errors>
+          <out-discards>8</out-discards>
+        </statistics>
+      </port>
+    </state>
+  </data>
+</rpc-reply>"""
+
+NOKIA_ROUTER_INTERFACE_XML = """
+<rpc-reply>
+  <data>
+    <state>
+      <router>
+        <interface>
+          <interface-name>lag-1.0</interface-name>
+          <statistics>
+            <ip>
+              <in-octets>11</in-octets>
+              <in-packets>12</in-packets>
+              <out-octets>13</out-octets>
+              <out-packets>14</out-packets>
+              <out-discard-packets>15</out-discard-packets>
+            </ip>
+          </statistics>
+          <ipv6>
+            <statistics>
+              <in-octets>16</in-octets>
+              <in-packets>17</in-packets>
+              <out-octets>18</out-octets>
+              <out-packets>19</out-packets>
+            </statistics>
+          </ipv6>
+        </interface>
+      </router>
+    </state>
+  </data>
+</rpc-reply>
+"""
+
+
+@pytest.fixture
+def nokia_port_doc_containing_every_field():
+    return etree.fromstring(NOKIA_PORT_XML)
+
+
+@pytest.fixture
+def nokia_lag_doc_containing_every_field():
+    return etree.fromstring(
+        NOKIA_PORT_XML.replace("port>", "lag>").replace(
+            "<port-id>1/1/c1</port-id>", "<lag-name>lag-1</lag-name>"
+        )
+    )
+
+
+@pytest.fixture
+def nokia_router_interface_doc_containing_every_field():
+    return etree.fromstring(NOKIA_ROUTER_INTERFACE_XML)
+
+
+def test_port_counters(nokia_port_doc_containing_every_field):
+    result = list(nokia._port_counters(nokia_port_doc_containing_every_field))
+    assert len(result) == 1
+    assert result[0] == {
+        "name": "1/1/c1",
+        "brian": {
+            "ingressOctets": 1,
+            "ingressPackets": 2,
+            "egressOctets": 3,
+            "egressPackets": 4,
+            "ingressErrors": 5,
+            "ingressDiscards": 6,
+            "egressErrors": 7,
+        },
+        "errors": {
+            "input_total_errors": 5,
+            "input_discards": 6,
+            "output_total_errors": 7,
+            "output_discards": 8,
+        },
+    }
+
+
+def test_lag_counters(nokia_lag_doc_containing_every_field):
+    result = list(nokia._lag_counters(nokia_lag_doc_containing_every_field))
+    assert len(result) == 1
+    assert result[0] == {
+        "name": "lag-1",
+        "brian": {
+            "ingressOctets": 1,
+            "ingressPackets": 2,
+            "egressOctets": 3,
+            "egressPackets": 4,
+            "ingressErrors": 5,
+            "ingressDiscards": 6,
+            "egressErrors": 7,
+        },
+        "errors": {
+            "input_total_errors": 5,
+            "input_discards": 6,
+            "output_total_errors": 7,
+            "output_discards": 8,
+        },
+    }
+
+
+def test_router_interface_counters(nokia_router_interface_doc_containing_every_field):
+    result = list(
+        nokia._router_interface_counters(
+            nokia_router_interface_doc_containing_every_field
+        )
+    )
+    assert len(result) == 1
+    assert result[0] == {
+        "name": "lag-1.0",
+        "brian": {
+            "ingressOctets": 11,
+            "ingressPackets": 12,
+            "egressOctets": 13,
+            "egressPackets": 14,
+            "ingressOctetsv6": 16,
+            "ingressPacketsv6": 17,
+            "egressOctetsv6": 18,
+            "egressPacketsv6": 19,
+        },
+        "errors": {
+            "output_discards": 15,
+        },
+    }
+
+
+def test_nokia_router_docs_do_not_generate_errors(
+    nokia_router_fqdn, caplog, get_netconf
+):
+    doc = get_netconf(nokia_router_fqdn)
+    counters = list(nokia.interface_counters(doc))
+    assert counters
+    assert not [r for r in caplog.records if r.levelname in ("ERROR", "WARNING")]
+
+
+def test_validate_interface_counters_and_influx_points_for_all_nokia_routers(
+    nokia_router_fqdn, get_netconf
+):
+    doc = get_netconf(nokia_router_fqdn)
+    interfaces = list(nokia.interface_counters(doc))
+    assert interfaces
+    for ifc in interfaces:
+        jsonschema.validate(ifc, common.INTERFACE_COUNTER_SCHEMA)
+
+    bpoints = list(
+        common.brian_points(
+            nokia_router_fqdn,
+            interfaces,
+            timestamp=datetime.now(),
+            measurement_name="blah",
+        )
+    )
+    assert bpoints
+    for point in bpoints:
+        jsonschema.validate(point, influx.INFLUX_POINT)
+        jsonschema.validate(point["fields"], common.BRIAN_POINT_FIELDS_SCHEMA)
+
+    epoints = list(
+        common.error_points(
+            nokia_router_fqdn,
+            interfaces,
+            timestamp=datetime.now(),
+            measurement_name="blah",
+        )
+    )
+    assert epoints
+    for point in epoints:
+        jsonschema.validate(point, influx.INFLUX_POINT)
+        jsonschema.validate(point["fields"], common.ERROR_POINT_FIELDS_SCHEMA)
+
+
+class TestGetNokiaNetconf:
+    RAW_RESPONSE_FILE = "raw-response-nokia-sample.xml"
+
+    @pytest.fixture(autouse=True)
+    def mocked_connection(self, data_dir):
+        raw_response = (data_dir / self.RAW_RESPONSE_FILE).read_bytes()
+        with patch.object(nokia, "netconf_connect") as mock:
+            mock().__enter__().get().tostring = raw_response
+            mock.reset_mock()
+            yield mock
+
+    def test_connect_with_params(self, mocked_connection):
+        nokia.get_netconf_interface_info("some.router", ssh_params={"some": "param"})
+
+        assert mocked_connection.call_args == call(
+            hostname="some.router",
+            ssh_params={"some": "param"},
+            device_params={"name": "sros"},
+            nc_params={"capabilities": ["urn:nokia.com:nc:pysros:pc"]},
+            timeout=60,
+        )
+
+    def test_calls_get_with_request_filter(self, mocked_connection):
+        router_name = "some-router"
+        nokia.get_netconf_interface_info(router_name, ssh_params={"some": "param"})
+
+        calls = mocked_connection().__enter__().get.call_args_list
+        assert len(calls) == 3
+        for i, kind in enumerate(["port", "lag"]):
+            elems = calls[i][1]["filter"].iter()
+            assert [e.tag for e in elems] == [
+                "filter",
+                "{urn:nokia.com:sros:ns:yang:sr:state}state",
+                "{urn:nokia.com:sros:ns:yang:sr:state}" + kind,
+            ]
+        elems = calls[2][1]["filter"].iter()
+        assert [e.tag for e in elems] == [
+            "filter",
+            "{urn:nokia.com:sros:ns:yang:sr:state}state",
+            "{urn:nokia.com:sros:ns:yang:sr:state}router",
+            "{urn:nokia.com:sros:ns:yang:sr:state}interface",
+        ]
+
+    def test_converts_rpc_response_to_xml(self):
+        router_name = "some-router"
+
+        doc = nokia.get_netconf_interface_info(
+            router_name, ssh_params={"some": "param"}
+        )
+
+        assert doc["port"].tag == "rpc-reply"
+        assert doc["lag"].tag == "rpc-reply"