]> arthur.barton.de Git - netdata.git/commitdiff
Merge pull request #1545 from l2isbad/haproxy_module
authorCosta Tsaousis <costa@tsaousis.gr>
Wed, 11 Jan 2017 18:16:52 +0000 (20:16 +0200)
committerGitHub <noreply@github.com>
Wed, 11 Jan 2017 18:16:52 +0000 (20:16 +0200)
Haproxy module

.gitignore
python.d/Makefile.am
python.d/README.md
python.d/cpufreq.chart.py
python.d/cpuidle.chart.py [new file with mode: 0644]
python.d/ipfs.chart.py
src/freebsd_sysctl.c
src/macos_sysctl.c

index 30962eaa59f0337cfb97cbe369fd8788702526d4..e5f27403d61f4424470224b179a28bece9d7cff1 100644 (file)
@@ -84,6 +84,8 @@ cmake_install.cmake
 
 .jetbrains*
 
+.DS_Store
+
 contrib/debian/changelog
 profile/benchmark-dictionary
 profile/benchmark-registry
index d142e5106a32ed228b6f0a392f140c5549711c0c..c8a33479bd52f1e3a0f4f1c69cae0ded1302d8d2 100644 (file)
@@ -12,6 +12,7 @@ dist_python_SCRIPTS = \
     apache_cache.chart.py \
     bind_rndc.chart.py \
     cpufreq.chart.py \
+    cpuidle.chart.py \
     dovecot.chart.py \
     example.chart.py \
     exim.chart.py \
index b7fb4e9f4706a04f9116f20f7cc4ef2ec61d7227..d0ad5120f2be4c59b6298cef8500edab5c1081fe 100644 (file)
@@ -186,13 +186,21 @@ If no configuration is given, module will attempt to read named.stats file  at `
 
 ---
 
-
 # cpufreq
 
-Module shows current cpu frequency by looking at appropriate files in /sys/devices
+This module shows the current CPU frequency as set by the cpufreq kernel
+module.
 
 **Requirement:**
-Processor which presents data scaling frequency data
+You need to have `CONFIG_CPU_FREQ` and (optionally) `CONFIG_CPU_FREQ_STAT`
+enabled in your kernel.
+
+This module tries to read from one of two possible locations. On
+initialization, it tries to read the `time_in_state` files provided by
+cpufreq\_stats. If this file does not exist, or doesn't contain valid data, it
+falls back to using the more inaccurate `scaling_cur_freq` file (which only
+represents the **current** CPU frequency, and doesn't account for any state
+changes which happen between updates).
 
 It produces one chart with multiple lines (one line per core).
 
@@ -204,11 +212,23 @@ Sample:
 sys_dir: "/sys/devices"
 ```
 
-If no configuration is given, module will search for `scaling_cur_freq` files in `/sys/devices` directory.
+If no configuration is given, module will search for cpufreq files in `/sys/devices` directory.
 Directory is also prefixed with `NETDATA_HOST_PREFIX` if specified.
 
 ---
 
+# cpuidle
+
+This module monitors the usage of CPU idle states.
+
+**Requirement:**
+Your kernel needs to have `CONFIG_CPU_IDLE` enabled.
+
+It produces one stacked chart per CPU, showing the percentage of time spent in
+each state.
+
+---
+
 # dovecot
 
 This module provides statistics information from dovecot server. 
index a9de5ceddcf7c010c214c7463919e23a9d1117b8..c761aae88a336cb02048725848071bbfa84c2c8b 100644 (file)
@@ -1,8 +1,10 @@
 # -*- coding: utf-8 -*-
 # Description: cpufreq netdata python.d module
-# Author: Pawel Krupa (paulfantom)
+# Author: Pawel Krupa (paulfantom) and Steven Noonan (tycho)
 
+import glob
 import os
+import time
 from base import SimpleService
 
 # default module values (can be overridden per job in `config`)
@@ -18,29 +20,53 @@ CHARTS = {
         ]}
 }
 
-
 class Service(SimpleService):
     def __init__(self, configuration=None, name=None):
         prefix = os.getenv('NETDATA_HOST_PREFIX', "")
         if prefix.endswith('/'):
             prefix = prefix[:-1]
         self.sys_dir = prefix + "/sys/devices"
-        self.filename = "scaling_cur_freq"
         SimpleService.__init__(self, configuration=configuration, name=name)
         self.order = ORDER
         self.definitions = CHARTS
         self._orig_name = ""
         self.assignment = {}
-        self.paths = []
+        self.accurate_exists = True
+        self.accurate_last = {}
 
     def _get_data(self):
-        raw = {}
-        for path in self.paths:
-            with open(path, 'r') as f:
-                raw[path] = f.read()
         data = {}
-        for path in self.paths:
-            data[self.assignment[path]] = raw[path]
+
+        if self.accurate_exists:
+            elapsed = time.time() - self.timetable['last']
+
+            accurate_ok = True
+
+            for name, paths in self.assignment.items():
+                last = self.accurate_last[name]
+                current = 0
+                for line in open(paths['accurate'], 'r'):
+                    line = list(map(int, line.split()))
+                    current += (line[0] * line[1]) / 100
+                delta = current - last
+                data[name] = delta
+                self.accurate_last[name] = current
+                if delta == 0 or abs(delta) > 1e7:
+                    # Delta is either too large or nonexistent, fall back to
+                    # less accurate reading. This can happen if we switch
+                    # to/from the 'schedutil' governor, which doesn't report
+                    # stats.
+                    accurate_ok = False
+
+            if accurate_ok:
+                return data
+            else:
+                self.alert("accurate method failed, falling back")
+
+
+        for name, paths in self.assignment.items():
+            data[name] = open(paths['inaccurate'], 'r').read()
+
         return data
 
     def check(self):
@@ -51,23 +77,30 @@ class Service(SimpleService):
 
         self._orig_name = self.chart_name
 
-        for dirpath, _, filenames in os.walk(self.sys_dir):
-            if self.filename in filenames:
-                self.paths.append(dirpath + "/" + self.filename)
-
-        if len(self.paths) == 0:
-            self.error("cannot find", self.filename)
+        for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/stats/time_in_state'):
+            path_elem = path.split('/')
+            cpu = path_elem[-4]
+            if cpu not in self.assignment:
+                self.assignment[cpu] = {}
+            self.assignment[cpu]['accurate'] = path
+            self.accurate_last[cpu] = 0
+
+        if len(self.assignment) == 0:
+            self.accurate_exists = False
+
+        for path in glob.glob(self.sys_dir + '/system/cpu/cpu*/cpufreq/scaling_cur_freq'):
+            path_elem = path.split('/')
+            cpu = path_elem[-3]
+            if cpu not in self.assignment:
+                self.assignment[cpu] = {}
+            self.assignment[cpu]['inaccurate'] = path
+
+        if len(self.assignment) == 0:
+            self.error("couldn't find a method to read cpufreq statistics")
             return False
 
-        self.paths.sort()
-        i = 0
-        for path in self.paths:
-            self.assignment[path] = "cpu" + str(i)
-            i += 1
-
-        for name in self.assignment:
-            dim = self.assignment[name]
-            self.definitions[ORDER[0]]['lines'].append([dim, dim, 'absolute', 1, 1000])
+        for name in self.assignment.keys():
+            self.definitions[ORDER[0]]['lines'].append([name, name, 'absolute', 1, 1000])
 
         return True
 
diff --git a/python.d/cpuidle.chart.py b/python.d/cpuidle.chart.py
new file mode 100644 (file)
index 0000000..f7199ae
--- /dev/null
@@ -0,0 +1,143 @@
+# -*- coding: utf-8 -*-
+# Description: cpuidle netdata python.d module
+# Author: Steven Noonan (tycho)
+
+import glob
+import os
+import platform
+import time
+from base import SimpleService
+
+import ctypes
+syscall = ctypes.CDLL('libc.so.6').syscall
+
+# default module values (can be overridden per job in `config`)
+# update_every = 2
+
+class Service(SimpleService):
+    def __init__(self, configuration=None, name=None):
+        prefix = os.getenv('NETDATA_HOST_PREFIX', "")
+        if prefix.endswith('/'):
+            prefix = prefix[:-1]
+        self.sys_dir = prefix + "/sys/devices/system/cpu"
+        self.schedstat_path = prefix + "/proc/schedstat"
+        SimpleService.__init__(self, configuration=configuration, name=name)
+        self.order = []
+        self.definitions = {}
+        self._orig_name = ""
+        self.assignment = {}
+
+    def __gettid(self):
+        # This is horrendous. We need the *thread id* (not the *process id*),
+        # but there's no Python standard library way of doing that. If you need
+        # to enable this module on a non-x86 machine type, you'll have to find
+        # the Linux syscall number for gettid() and add it to the dictionary
+        # below.
+        syscalls = {
+            'i386':    224,
+            'x86_64':  186,
+        }
+        if platform.machine() not in syscalls:
+            return None
+        tid = syscall(syscalls[platform.machine()])
+        return tid
+
+    def __wake_cpus(self):
+        # Requires Python 3.3+. This will "tickle" each CPU to force it to
+        # update its idle counters.
+        if hasattr(os, 'sched_setaffinity'):
+            pid = self.__gettid()
+            save_affinity = os.sched_getaffinity(pid)
+            for idx in range(0, len(self.assignment)):
+                os.sched_setaffinity(pid, [idx])
+                os.sched_getaffinity(pid)
+            os.sched_setaffinity(pid, save_affinity)
+
+    def __read_schedstat(self):
+        cpus = {}
+        for line in open(self.schedstat_path, 'r'):
+            if not line.startswith('cpu'):
+                continue
+            line = line.rstrip().split()
+            cpu = line[0]
+            active_time = line[7]
+            cpus[cpu] = int(active_time) // 1000
+        return cpus
+
+    def _get_data(self):
+        results = {}
+
+        # This line is critical for the stats to update. If we don't "tickle"
+        # all the CPUs, then all the counters stop counting.
+        self.__wake_cpus()
+
+        # Use the kernel scheduler stats to determine how much time was spent
+        # in C0 (active).
+        schedstat = self.__read_schedstat()
+
+        for cpu, metrics in self.assignment.items():
+            update_time = schedstat[cpu]
+            results[cpu + '_active_time'] = update_time
+
+            for metric, path in metrics.items():
+                residency = int(open(path, 'r').read())
+                results[metric] = residency
+
+        return results
+
+    def check(self):
+        if self.__gettid() is None:
+            self.error("Cannot get thread ID. Stats would be completely broken.")
+            return False
+
+        self._orig_name = self.chart_name
+
+        for path in sorted(glob.glob(self.sys_dir + '/cpu*/cpuidle/state*/name')):
+            # ['', 'sys', 'devices', 'system', 'cpu', 'cpu0', 'cpuidle', 'state3', 'name']
+            path_elem = path.split('/')
+            cpu = path_elem[-4]
+            state = path_elem[-2]
+            statename = open(path, 'rt').read().rstrip()
+
+            orderid = '%s_cpuidle' % (cpu,)
+            if orderid not in self.definitions:
+                self.order.append(orderid)
+                active_name = '%s_active_time' % (cpu,)
+                self.definitions[orderid] = {
+                    'options': [None, 'C-state residency', 'time%', 'cpuidle', None, 'stacked'],
+                    'lines': [
+                        [active_name, 'C0 (active)', 'percentage-of-incremental-row', 1, 1],
+                    ],
+                }
+                self.assignment[cpu] = {}
+
+            defid = '%s_%s_time' % (orderid, state)
+
+            self.definitions[orderid]['lines'].append(
+                [defid, statename, 'percentage-of-incremental-row', 1, 1]
+            )
+
+            self.assignment[cpu][defid] = '/'.join(path_elem[:-1] + ['time'])
+
+        # Sort order by kernel-specified CPU index
+        self.order.sort(key=lambda x: int(x.split('_')[0][3:]))
+
+        if len(self.definitions) == 0:
+            self.error("couldn't find cstate stats")
+            return False
+
+        return True
+
+    def create(self):
+        self.chart_name = "cpu"
+        status = SimpleService.create(self)
+        self.chart_name = self._orig_name
+        return status
+
+    def update(self, interval):
+        self.chart_name = "cpu"
+        status = SimpleService.update(self, interval=interval)
+        self.chart_name = self._orig_name
+        return status
+
+# vim: set ts=4 sts=4 sw=4 et:
index b0b2a9659cf95ca11e8bc55a9b92da1e8717973a..89c7fbf6e040f66cbe1a75fe1a50343fb4948de8 100644 (file)
@@ -19,7 +19,7 @@ retries = 60
 # }}
 
 # charts order (can be overridden if you want less charts, or different order)
-ORDER = ['bandwidth', 'peers']
+ORDER = ['bandwidth', 'peers', 'repo_size', 'repo_objects']
 
 CHARTS = {
     'bandwidth': {
@@ -32,10 +32,21 @@ CHARTS = {
         'options': [None, 'IPFS Peers', 'peers', 'Peers', 'ipfs.peers', 'line'],
         'lines': [
             ["peers", None, 'absolute']
-        ]}
+        ]},
+    'repo_size': {
+        'options': [None, 'IPFS Repo Size', 'MB', 'Size', 'ipfs.repo_size', 'line'],
+        'lines': [
+            ["size", None, "absolute", 1, 1000000]
+        ]},
+    'repo_objects': {
+        'options': [None, 'IPFS Repo Objects', 'objects', 'Objects', 'ipfs.repo_objects', 'line'],
+        'lines': [
+            ["objects", None, "absolute", 1, 1],
+            ["pinned", None, "absolute", 1, 1],
+            ["recursive_pins", None, "absolute", 1, 1]
+        ]},
 }
 
-
 class Service(UrlService):
     def __init__(self, configuration=None, name=None):
         UrlService.__init__(self, configuration=configuration, name=name)
@@ -46,62 +57,44 @@ class Service(UrlService):
         self.order = ORDER
         self.definitions = CHARTS
 
-    def _get_bandwidth(self):
-        """
-        Format data received from http request
-        :return: int, int
+    def _get_json(self, suburl):
         """
-        self.url = self.baseurl + "/api/v0/stats/bw"
+        :return: json decoding of the specified url
+        """ 
+        self.url = self.baseurl + suburl
         try:
-            raw = self._get_raw_data()
-        except AttributeError:
-            return None
-
-        try:
-            parsed = json.loads(raw)
-            bw_in = int(parsed['RateIn'])
-            bw_out = int(parsed['RateOut'])
+            return json.loads(self._get_raw_data()) 
         except:
-            return None
-
-        return bw_in, bw_out
+            return {}
 
-    def _get_peers(self):
-        """
-        Format data received from http request
-        :return: int
-        """
-        self.url = self.baseurl + "/api/v0/swarm/peers"
-        try:
-            raw = self._get_raw_data()
-        except AttributeError:
-            return None
-
-        try:
-            parsed = json.loads(raw)
-            peers = len(parsed['Strings'])
-        except:
-            return None
+    def _recursive_pins(self, keys):
+        return len([k for k in keys if keys[k]["Type"] == b"recursive"])
 
-        return peers
 
     def _get_data(self):
         """
         Get data from API
         :return: dict
         """
-        try:
-            peers = self._get_peers()
-            bandwidth_in, bandwidth_out = self._get_bandwidth()
-        except:
-            return None
-        data = {}
-        if peers is not None:
-            data['peers'] = peers
-        if bandwidth_in is not None and bandwidth_out is not None:
-            data['in'] = bandwidth_in
-            data['out'] = bandwidth_out
+        cfg = {# suburl : List of (result-key, original-key, transform-func)
+               '/api/v0/stats/bw'   :[('in', 'RateIn', int ),
+                                      ('out', 'RateOut', int )],
+               '/api/v0/swarm/peers':[('peers', 'Strings', len )],
+               '/api/v0/stats/repo' :[('size', 'RepoSize', int),
+                                      ('objects', 'NumObjects', int)],
+               '/api/v0/pin/ls': [('pinned', 'Keys', len),
+                                  ('recursive_pins', 'Keys', self._recursive_pins)
+                                 ]
+        }
+        r = {}
+        for suburl in cfg:
+            json = self._get_json(suburl)
+            for newkey, origkey, xmute in cfg[suburl]:
+                try:
+                    r[newkey] = xmute(json[origkey])
+                except: pass
+        return r or None
+
+
 
-        if len(data) == 0:
-            return None
-        return data
index 202bff1252a97dd6d32c5b67876f66f8c49a5254..26c5f9c379756664e93c782c92a62dc6a8bc9d6a 100644 (file)
@@ -15,7 +15,6 @@
 // NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
 #include <net/netisr.h>
 // NEEDED BY: struct ifaddrs, getifaddrs()
-#define _IFI_OQDROPS // It is for FreeNAS only. Most probably in future releases of FreeNAS it will be removed
 #include <net/if.h>
 #include <ifaddrs.h>
 // NEEDED BY do_tcp...
@@ -98,6 +97,8 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
         do_tcpext_connaborts    = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
         do_udp_packets          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP packets", 1);
         do_udp_errors           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 UDP errors", 1);
+        do_icmp_packets         = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP packets", 1);
+        do_icmpmsg              = config_get_boolean("plugin:freebsd:sysctl", "ipv4 ICMP messages", 1);
         do_ip_packets           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 packets", 1);
         do_ip_fragsout          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments sent", 1);
         do_ip_fragsin           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 fragments assembly", 1);
@@ -1280,14 +1281,14 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                     st->isdetail = 1;
 
                     rrddim_add(st, "inbound", NULL, 1, 1, RRDDIM_INCREMENTAL);
-#ifdef __IFI_OQDROPS
+#if __FreeBSD__ >= 11
                     rrddim_add(st, "outbound", NULL, -1, 1, RRDDIM_INCREMENTAL);
 #endif
                 }
                 else rrdset_next(st);
 
                 rrddim_set(st, "inbound", IFA_DATA(iqdrops));
-#ifdef __IFI_OQDROPS
+#if __FreeBSD__ >= 11
                 rrddim_set(st, "outbound", IFA_DATA(oqdrops));
 #endif
                 rrdset_done(st);
index 1f02a63b121bece5195426b3cf1dbd48aa736c9e..1c680a825798ef02f2aa403fc884ea162dea99d7 100644 (file)
@@ -2,6 +2,21 @@
 #include <sys/sysctl.h>
 // NEEDED BY: do_bandwidth
 #include <net/route.h>
+// NEEDED BY do_tcp...
+#include <sys/socketvar.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+// NEEDED BY do_udp..., do_ip...
+#include <netinet/ip_var.h>
+// NEEDED BY do_udp...
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+// NEEDED BY do_icmp...
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h>
+#include <netinet/icmp_var.h>
+// NEEDED BY do_icmp6...
+#include <netinet/icmp6.h>
 
 #define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
 
@@ -13,12 +28,46 @@ int getsysctl(const char *name, void *ptr, size_t len);
 int do_macos_sysctl(int update_every, usec_t dt) {
     (void)dt;
 
-    static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1;
+    static int do_loadavg = -1, do_swap = -1, do_bandwidth = -1,
+               do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_ecn = -1,
+               do_tcpext_syscookies = -1, do_tcpext_ofo = -1, do_tcpext_connaborts = -1,
+               do_udp_packets = -1, do_udp_errors = -1, do_icmp_packets = -1, do_icmpmsg = -1,
+               do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1,
+               do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1,
+               do_icmp6 = -1, do_icmp6_redir = -1, do_icmp6_errors = -1, do_icmp6_echos = -1,
+               do_icmp6_router = -1, do_icmp6_neighbor = -1, do_icmp6_types = -1;
+
 
     if (unlikely(do_loadavg == -1)) {
         do_loadavg              = config_get_boolean("plugin:macos:sysctl", "enable load average", 1);
         do_swap                 = config_get_boolean("plugin:macos:sysctl", "system swap", 1);
         do_bandwidth            = config_get_boolean("plugin:macos:sysctl", "bandwidth", 1);
+        do_tcp_packets          = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP packets", 1);
+        do_tcp_errors           = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP errors", 1);
+        do_tcp_handshake        = config_get_boolean("plugin:macos:sysctl", "ipv4 TCP handshake issues", 1);
+        do_ecn                  = config_get_boolean_ondemand("plugin:macos:sysctl", "ECN packets", CONFIG_ONDEMAND_ONDEMAND);
+        do_tcpext_syscookies    = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP SYN cookies", CONFIG_ONDEMAND_ONDEMAND);
+        do_tcpext_ofo           = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP out-of-order queue", CONFIG_ONDEMAND_ONDEMAND);
+        do_tcpext_connaborts    = config_get_boolean_ondemand("plugin:macos:sysctl", "TCP connection aborts", CONFIG_ONDEMAND_ONDEMAND);
+        do_udp_packets          = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP packets", 1);
+        do_udp_errors           = config_get_boolean("plugin:macos:sysctl", "ipv4 UDP errors", 1);
+        do_icmp_packets         = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP packets", 1);
+        do_icmpmsg              = config_get_boolean("plugin:macos:sysctl", "ipv4 ICMP messages", 1);
+        do_ip_packets           = config_get_boolean("plugin:macos:sysctl", "ipv4 packets", 1);
+        do_ip_fragsout          = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments sent", 1);
+        do_ip_fragsin           = config_get_boolean("plugin:macos:sysctl", "ipv4 fragments assembly", 1);
+        do_ip_errors            = config_get_boolean("plugin:macos:sysctl", "ipv4 errors", 1);
+        do_ip6_packets          = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 packets", CONFIG_ONDEMAND_ONDEMAND);
+        do_ip6_fragsout         = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments sent", CONFIG_ONDEMAND_ONDEMAND);
+        do_ip6_fragsin          = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 fragments assembly", CONFIG_ONDEMAND_ONDEMAND);
+        do_ip6_errors           = config_get_boolean_ondemand("plugin:macos:sysctl", "ipv6 errors", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6                = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_redir          = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp redirects", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_errors         = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp errors", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_echos          = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp echos", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_router         = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp router", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_neighbor       = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp neighbor", CONFIG_ONDEMAND_ONDEMAND);
+        do_icmp6_types          = config_get_boolean_ondemand("plugin:macos:sysctl", "icmp types", CONFIG_ONDEMAND_ONDEMAND);
     }
 
     RRDSET *st;
@@ -45,6 +94,120 @@ int do_macos_sysctl(int update_every, usec_t dt) {
         u_long  ift_obytes;
     } iftot = {0, 0};
 
+    // NEEDED BY: do_tcp...
+    struct tcpstat tcpstat;
+    uint64_t tcps_states[TCP_NSTATES];
+
+    // NEEDED BY: do_udp...
+    struct udpstat udpstat;
+
+    // NEEDED BY: do_icmp...
+    struct icmpstat icmpstat;
+    struct icmp_total {
+        u_long  msgs_in;
+        u_long  msgs_out;
+    } icmp_total = {0, 0};
+
+    // NEEDED BY: do_ip...
+    struct ipstat ipstat;
+
+    // NEEDED BY: do_ip6...
+    /*
+     * Dirty workaround for /usr/include/netinet6/ip6_var.h absence.
+     * Struct ip6stat was copied from bsd/netinet6/ip6_var.h from xnu sources.
+     */
+#define        IP6S_SRCRULE_COUNT 16
+#include <netinet6/scope6_var.h>
+    struct     ip6stat {
+        u_quad_t ip6s_total;           /* total packets received */
+        u_quad_t ip6s_tooshort;                /* packet too short */
+        u_quad_t ip6s_toosmall;                /* not enough data */
+        u_quad_t ip6s_fragments;       /* fragments received */
+        u_quad_t ip6s_fragdropped;     /* frags dropped(dups, out of space) */
+        u_quad_t ip6s_fragtimeout;     /* fragments timed out */
+        u_quad_t ip6s_fragoverflow;    /* fragments that exceeded limit */
+        u_quad_t ip6s_forward;         /* packets forwarded */
+        u_quad_t ip6s_cantforward;     /* packets rcvd for unreachable dest */
+        u_quad_t ip6s_redirectsent;    /* packets forwarded on same net */
+        u_quad_t ip6s_delivered;       /* datagrams delivered to upper level */
+        u_quad_t ip6s_localout;                /* total ip packets generated here */
+        u_quad_t ip6s_odropped;                /* lost packets due to nobufs, etc. */
+        u_quad_t ip6s_reassembled;     /* total packets reassembled ok */
+        u_quad_t ip6s_atmfrag_rcvd;    /* atomic fragments received */
+        u_quad_t ip6s_fragmented;      /* datagrams successfully fragmented */
+        u_quad_t ip6s_ofragments;      /* output fragments created */
+        u_quad_t ip6s_cantfrag;                /* don't fragment flag was set, etc. */
+        u_quad_t ip6s_badoptions;      /* error in option processing */
+        u_quad_t ip6s_noroute;         /* packets discarded due to no route */
+        u_quad_t ip6s_badvers;         /* ip6 version != 6 */
+        u_quad_t ip6s_rawout;          /* total raw ip packets generated */
+        u_quad_t ip6s_badscope;                /* scope error */
+        u_quad_t ip6s_notmember;       /* don't join this multicast group */
+        u_quad_t ip6s_nxthist[256];    /* next header history */
+        u_quad_t ip6s_m1;              /* one mbuf */
+        u_quad_t ip6s_m2m[32];         /* two or more mbuf */
+        u_quad_t ip6s_mext1;           /* one ext mbuf */
+        u_quad_t ip6s_mext2m;          /* two or more ext mbuf */
+        u_quad_t ip6s_exthdrtoolong;   /* ext hdr are not continuous */
+        u_quad_t ip6s_nogif;           /* no match gif found */
+        u_quad_t ip6s_toomanyhdr;      /* discarded due to too many headers */
+
+        /*
+         * statistics for improvement of the source address selection
+         * algorithm:
+         */
+        /* number of times that address selection fails */
+        u_quad_t ip6s_sources_none;
+        /* number of times that an address on the outgoing I/F is chosen */
+        u_quad_t ip6s_sources_sameif[SCOPE6_ID_MAX];
+        /* number of times that an address on a non-outgoing I/F is chosen */
+        u_quad_t ip6s_sources_otherif[SCOPE6_ID_MAX];
+        /*
+         * number of times that an address that has the same scope
+         * from the destination is chosen.
+         */
+        u_quad_t ip6s_sources_samescope[SCOPE6_ID_MAX];
+        /*
+         * number of times that an address that has a different scope
+         * from the destination is chosen.
+         */
+        u_quad_t ip6s_sources_otherscope[SCOPE6_ID_MAX];
+        /* number of times that a deprecated address is chosen */
+        u_quad_t ip6s_sources_deprecated[SCOPE6_ID_MAX];
+
+        u_quad_t ip6s_forward_cachehit;
+        u_quad_t ip6s_forward_cachemiss;
+
+        /* number of times that each rule of source selection is applied. */
+        u_quad_t ip6s_sources_rule[IP6S_SRCRULE_COUNT];
+
+        /* number of times we ignored address on expensive secondary interfaces */
+        u_quad_t ip6s_sources_skip_expensive_secondary_if;
+
+        /* pkt dropped, no mbufs for control data */
+        u_quad_t ip6s_pktdropcntrl;
+
+        /* total packets trimmed/adjusted  */
+        u_quad_t ip6s_adj;
+        /* hwcksum info discarded during adjustment */
+        u_quad_t ip6s_adj_hwcsum_clr;
+
+        /* duplicate address detection collisions */
+        u_quad_t ip6s_dad_collide;
+
+        /* DAD NS looped back */
+        u_quad_t ip6s_dad_loopcount;
+    } ip6stat;
+
+    // NEEDED BY: do_icmp6...
+    struct icmp6stat icmp6stat;
+    struct icmp6_total {
+        u_long  msgs_in;
+        u_long  msgs_out;
+    } icmp6_total = {0, 0};
+
+    // --------------------------------------------------------------------
+
     if (last_loadavg_usec <= dt) {
         if (likely(do_loadavg)) {
             if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
@@ -72,6 +235,8 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     }
     else last_loadavg_usec -= dt;
 
+    // --------------------------------------------------------------------
+
     if (likely(do_swap)) {
         if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
             do_swap = 0;
@@ -142,6 +307,764 @@ int do_macos_sysctl(int update_every, usec_t dt) {
         }
     }
 
+    // --------------------------------------------------------------------
+
+    // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
+    if (likely(do_tcp_packets || do_tcp_errors || do_tcp_handshake || do_tcpext_connaborts || do_tcpext_ofo || do_tcpext_syscookies || do_ecn)) {
+        if (unlikely(GETSYSCTL("net.inet.tcp.stats", tcpstat))){
+            do_tcp_packets = 0;
+            error("DISABLED: ipv4.tcppackets");
+            do_tcp_errors = 0;
+            error("DISABLED: ipv4.tcperrors");
+            do_tcp_handshake = 0;
+            error("DISABLED: ipv4.tcphandshake");
+            do_tcpext_connaborts = 0;
+            error("DISABLED: ipv4.tcpconnaborts");
+            do_tcpext_ofo = 0;
+            error("DISABLED: ipv4.tcpofo");
+            do_tcpext_syscookies = 0;
+            error("DISABLED: ipv4.tcpsyncookies");
+            do_ecn = 0;
+            error("DISABLED: ipv4.ecnpkts");
+        } else {
+            if (likely(do_tcp_packets)) {
+                st = rrdset_find("ipv4.tcppackets");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
+                                       "packets/s",
+                                       2600, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InSegs", "received", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutSegs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
+                rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_tcp_errors)) {
+                st = rrdset_find("ipv4.tcperrors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
+                                       "packets/s",
+                                       2700, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InErrs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "RetransSegs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
+                rrddim_set(st, "InCsumErrors", tcpstat.tcps_rcvbadsum);
+                rrddim_set(st, "RetransSegs", tcpstat.tcps_sndrexmitpack);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_tcp_handshake)) {
+                st = rrdset_find("ipv4.tcphandshake");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcphandshake", NULL, "tcp", NULL,
+                                       "IPv4 TCP Handshake Issues",
+                                       "events/s", 2900, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "EstabResets", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "AttemptFails", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "EstabResets", tcpstat.tcps_drops);
+                rrddim_set(st, "ActiveOpens", tcpstat.tcps_connattempt);
+                rrddim_set(st, "PassiveOpens", tcpstat.tcps_accepts);
+                rrddim_set(st, "AttemptFails", tcpstat.tcps_conndrops);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_tcpext_connaborts == CONFIG_ONDEMAND_YES || (do_tcpext_connaborts == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop))) {
+                do_tcpext_connaborts = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.tcpconnaborts");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "TCPAbortOnData",    "baddata",     1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "TCPAbortOnClose",   "userclosed",  1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "TCPAbortOnMemory",  "nomemory",    1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "TCPAbortOnTimeout", "timeout",     1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "TCPAbortOnData",    tcpstat.tcps_rcvpackafterwin);
+                rrddim_set(st, "TCPAbortOnClose",   tcpstat.tcps_rcvafterclose);
+                rrddim_set(st, "TCPAbortOnMemory",  tcpstat.tcps_rcvmemdrop);
+                rrddim_set(st, "TCPAbortOnTimeout", tcpstat.tcps_persistdrop);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_tcpext_ofo == CONFIG_ONDEMAND_YES || (do_tcpext_ofo == CONFIG_ONDEMAND_ONDEMAND && tcpstat.tcps_rcvoopack)) {
+                do_tcpext_ofo = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.tcpofo");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "TCPOFOQueue", "inqueue",  1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "TCPOFOQueue",   tcpstat.tcps_rcvoopack);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_tcpext_syscookies == CONFIG_ONDEMAND_YES || (do_tcpext_syscookies == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+                do_tcpext_syscookies = CONFIG_ONDEMAND_YES;
+
+                st = rrdset_find("ipv4.tcpsyncookies");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "SyncookiesRecv",   "received",  1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "SyncookiesSent",   "sent",     -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "SyncookiesFailed", "failed",   -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "SyncookiesRecv",   tcpstat.tcps_sc_recvcookie);
+                rrddim_set(st, "SyncookiesSent",   tcpstat.tcps_sc_sendcookie);
+                rrddim_set(st, "SyncookiesFailed", tcpstat.tcps_sc_zonefail);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_ecn == CONFIG_ONDEMAND_YES || (do_ecn == CONFIG_ONDEMAND_ONDEMAND && (tcpstat.tcps_ecn_recv_ce || tcpstat.tcps_ecn_not_supported))) {
+                do_ecn = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv4.ecnpkts");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRDDIM_INCREMENTAL);
+                }
+                else rrdset_next(st);
+
+                rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_recv_ce);
+                rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_not_supported);
+                rrdset_done(st);
+            }
+
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    // see http://net-snmp.sourceforge.net/docs/mibs/udp.html
+    if (likely(do_udp_packets || do_udp_errors)) {
+        if (unlikely(GETSYSCTL("net.inet.udp.stats", udpstat))) {
+            do_udp_packets = 0;
+            error("DISABLED: ipv4.udppackets");
+            do_udp_errors = 0;
+            error("DISABLED: ipv4.udperrors");
+        } else {
+            if (likely(do_udp_packets)) {
+                st = rrdset_find("ipv4.udppackets");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
+                                       "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InDatagrams", "received", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InDatagrams", udpstat.udps_ipackets);
+                rrddim_set(st, "OutDatagrams", udpstat.udps_opackets);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_udp_errors)) {
+                st = rrdset_find("ipv4.udperrors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
+                                       2701, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "NoPorts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InErrors", udpstat.udps_hdrops + udpstat.udps_badlen);
+                rrddim_set(st, "NoPorts", udpstat.udps_noport);
+                rrddim_set(st, "RcvbufErrors", udpstat.udps_fullsock);
+                rrddim_set(st, "InCsumErrors", udpstat.udps_badsum + udpstat.udps_nosum);
+                rrddim_set(st, "IgnoredMulti", udpstat.udps_filtermcast);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if (likely(do_icmp_packets || do_icmpmsg)) {
+        if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+            do_icmp_packets = 0;
+            error("DISABLED: ipv4.icmp");
+            error("DISABLED: ipv4.icmp_errors");
+            do_icmpmsg = 0;
+            error("DISABLED: ipv4.icmpmsg");
+        } else {
+            for (i = 0; i <= ICMP_MAXTYPE; i++) {
+                icmp_total.msgs_in += icmpstat.icps_inhist[i];
+                icmp_total.msgs_out += icmpstat.icps_outhist[i];
+            }
+            icmp_total.msgs_in += icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort;
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_icmp_packets)) {
+                st = rrdset_find("ipv4.icmp");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
+                                       2602,
+                                       update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InMsgs", "received", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutMsgs", "sent", -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InMsgs", icmp_total.msgs_in);
+                rrddim_set(st, "OutMsgs", icmp_total.msgs_out);
+
+                rrdset_done(st);
+
+                // --------------------------------------------------------------------
+
+                st = rrdset_find("ipv4.icmp_errors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
+                                       "packets/s",
+                                       2603, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InErrors", icmpstat.icps_badcode + icmpstat.icps_badlen + icmpstat.icps_checksum + icmpstat.icps_tooshort);
+                rrddim_set(st, "OutErrors", icmpstat.icps_error);
+                rrddim_set(st, "InCsumErrors", icmpstat.icps_checksum);
+
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_icmpmsg)) {
+                st = rrdset_find("ipv4.icmpmsg");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
+                                       "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InEchoReps", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                    rrddim_set(st, "InEchoReps", icmpstat.icps_inhist[ICMP_ECHOREPLY]);
+                    rrddim_set(st, "OutEchoReps", icmpstat.icps_outhist[ICMP_ECHOREPLY]);
+                    rrddim_set(st, "InEchos", icmpstat.icps_inhist[ICMP_ECHO]);
+                    rrddim_set(st, "OutEchos", icmpstat.icps_outhist[ICMP_ECHO]);
+
+                rrdset_done(st);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    // see also http://net-snmp.sourceforge.net/docs/mibs/ip.html
+    if (likely(do_ip_packets || do_ip_fragsout || do_ip_fragsin || do_ip_errors)) {
+        if (unlikely(GETSYSCTL("net.inet.ip.stats", ipstat))) {
+            do_ip_packets = 0;
+            error("DISABLED: ipv4.packets");
+            do_ip_fragsout = 0;
+            error("DISABLED: ipv4.fragsout");
+            do_ip_fragsin = 0;
+            error("DISABLED: ipv4.fragsin");
+            do_ip_errors = 0;
+            error("DISABLED: ipv4.errors");
+        } else {
+            if (likely(do_ip_packets)) {
+                st = rrdset_find("ipv4.packets");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
+                                       3000, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InReceives", "received", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutRequests", "sent", -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InDelivers", "delivered", 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "OutRequests", ipstat.ips_localout);
+                rrddim_set(st, "InReceives", ipstat.ips_total);
+                rrddim_set(st, "ForwDatagrams", ipstat.ips_forward);
+                rrddim_set(st, "InDelivers", ipstat.ips_delivered);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_ip_fragsout)) {
+                st = rrdset_find("ipv4.fragsout");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
+                                       "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "FragOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "FragFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "FragCreates", "created", 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "FragOKs", ipstat.ips_fragmented);
+                rrddim_set(st, "FragFails", ipstat.ips_cantfrag);
+                rrddim_set(st, "FragCreates", ipstat.ips_ofragments);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_ip_fragsin)) {
+                st = rrdset_find("ipv4.fragsin");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "fragsin", NULL, "fragments", NULL,
+                                       "IPv4 Fragments Reassembly",
+                                       "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ReasmFails", "failed", -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "ReasmReqds", "all", 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "ReasmOKs", ipstat.ips_fragments);
+                rrddim_set(st, "ReasmFails", ipstat.ips_fragdropped);
+                rrddim_set(st, "ReasmReqds", ipstat.ips_reassembled);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_ip_errors)) {
+                st = rrdset_find("ipv4.errors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
+                                       3002,
+                                       update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InDiscards", ipstat.ips_badsum + ipstat.ips_tooshort + ipstat.ips_toosmall + ipstat.ips_toolong);
+                rrddim_set(st, "OutDiscards", ipstat.ips_odropped);
+                rrddim_set(st, "InHdrErrors", ipstat.ips_badhlen + ipstat.ips_badlen + ipstat.ips_badoptions + ipstat.ips_badvers);
+                rrddim_set(st, "InAddrErrors", ipstat.ips_badaddr);
+                rrddim_set(st, "InUnknownProtos", ipstat.ips_noproto);
+                rrddim_set(st, "OutNoRoutes", ipstat.ips_noroute);
+                rrdset_done(st);
+            }
+        }
+    }
+    // --------------------------------------------------------------------
+
+    if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
+        if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+            do_ip6_packets = 0;
+            error("DISABLED: ipv6.packets");
+            do_ip6_fragsout = 0;
+            error("DISABLED: ipv6.fragsout");
+            do_ip6_fragsin = 0;
+            error("DISABLED: ipv6.fragsin");
+            do_ip6_errors = 0;
+            error("DISABLED: ipv6.errors");
+        } else {
+            if (do_ip6_packets == CONFIG_ONDEMAND_YES || (do_ip6_packets == CONFIG_ONDEMAND_ONDEMAND &&
+                                                          (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
+                                                           ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
+                do_ip6_packets = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.packets");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
+                                       update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "forwarded", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "delivers", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "sent", ip6stat.ip6s_localout);
+                rrddim_set(st, "received", ip6stat.ip6s_total);
+                rrddim_set(st, "forwarded", ip6stat.ip6s_forward);
+                rrddim_set(st, "delivers", ip6stat.ip6s_delivered);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_ip6_fragsout == CONFIG_ONDEMAND_YES || (do_ip6_fragsout == CONFIG_ONDEMAND_ONDEMAND &&
+                                                           (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
+                                                            ip6stat.ip6s_ofragments))) {
+                do_ip6_fragsout = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.fragsout");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
+                                       "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "ok", ip6stat.ip6s_fragmented);
+                rrddim_set(st, "failed", ip6stat.ip6s_cantfrag);
+                rrddim_set(st, "all", ip6stat.ip6s_ofragments);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_ip6_fragsin == CONFIG_ONDEMAND_YES || (do_ip6_fragsin == CONFIG_ONDEMAND_ONDEMAND &&
+                                                          (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
+                                                           ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
+                do_ip6_fragsin = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.fragsin");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
+                                       "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "ok", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "failed", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "timeout", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "all", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "ok", ip6stat.ip6s_reassembled);
+                rrddim_set(st, "failed", ip6stat.ip6s_fragdropped);
+                rrddim_set(st, "timeout", ip6stat.ip6s_fragtimeout);
+                rrddim_set(st, "all", ip6stat.ip6s_fragments);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_ip6_errors == CONFIG_ONDEMAND_YES || (do_ip6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+                    ip6stat.ip6s_toosmall ||
+                    ip6stat.ip6s_odropped ||
+                    ip6stat.ip6s_badoptions ||
+                    ip6stat.ip6s_badvers ||
+                    ip6stat.ip6s_exthdrtoolong ||
+                    ip6stat.ip6s_sources_none ||
+                    ip6stat.ip6s_tooshort ||
+                    ip6stat.ip6s_cantforward ||
+                    ip6stat.ip6s_noroute))) {
+                do_ip6_errors = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.errors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
+                                       update_every, RRDSET_TYPE_LINE);
+                    st->isdetail = 1;
+
+                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InDiscards", ip6stat.ip6s_toosmall);
+                rrddim_set(st, "OutDiscards", ip6stat.ip6s_odropped);
+
+                rrddim_set(st, "InHdrErrors",
+                           ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers + ip6stat.ip6s_exthdrtoolong);
+                rrddim_set(st, "InAddrErrors", ip6stat.ip6s_sources_none);
+                rrddim_set(st, "InTruncatedPkts", ip6stat.ip6s_tooshort);
+                rrddim_set(st, "InNoRoutes", ip6stat.ip6s_cantforward);
+
+                rrddim_set(st, "OutNoRoutes", ip6stat.ip6s_noroute);
+                rrdset_done(st);
+            }
+        }
+    }
+
+    // --------------------------------------------------------------------
+
+    if (likely(do_icmp6 || do_icmp6_redir || do_icmp6_errors || do_icmp6_echos || do_icmp6_router || do_icmp6_neighbor || do_icmp6_types)) {
+        if (unlikely(GETSYSCTL("net.inet6.icmp6.stats", icmp6stat))) {
+            do_icmp6 = 0;
+            error("DISABLED: ipv6.icmp");
+        } else {
+            for (i = 0; i <= ICMP6_MAXTYPE; i++) {
+                icmp6_total.msgs_in += icmp6stat.icp6s_inhist[i];
+                icmp6_total.msgs_out += icmp6stat.icp6s_outhist[i];
+            }
+            icmp6_total.msgs_in += icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort;
+            if (do_icmp6 == CONFIG_ONDEMAND_YES || (do_icmp6 == CONFIG_ONDEMAND_ONDEMAND && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
+                do_icmp6 = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmp");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
+                                       "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "sent", icmp6_total.msgs_in);
+                rrddim_set(st, "received", icmp6_total.msgs_out);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_redir == CONFIG_ONDEMAND_YES || (do_icmp6_redir == CONFIG_ONDEMAND_ONDEMAND && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
+                do_icmp6_redir = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmpredir");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
+                                       "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "received", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "sent", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "sent", icmp6stat.icp6s_inhist[ND_REDIRECT]);
+                rrddim_set(st, "received", icmp6stat.icp6s_outhist[ND_REDIRECT]);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_errors == CONFIG_ONDEMAND_YES || (do_icmp6_errors == CONFIG_ONDEMAND_ONDEMAND && (
+                                                                            icmp6stat.icp6s_badcode ||
+                                                                            icmp6stat.icp6s_badlen ||
+                                                                            icmp6stat.icp6s_checksum ||
+                                                                            icmp6stat.icp6s_tooshort ||
+                                                                            icmp6stat.icp6s_error ||
+                                                                            icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH] ||
+                                                                            icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED] ||
+                                                                            icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB] ||
+                                                                            icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH] ||
+                                                                            icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED] ||
+                                                                            icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]))) {
+                do_icmp6_errors = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmperrors");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutErrors", NULL, -1, 1, RRDDIM_INCREMENTAL);
+
+                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InParmProblems", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InErrors", icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen + icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
+                rrddim_set(st, "OutErrors", icmp6stat.icp6s_error);
+                rrddim_set(st, "InCsumErrors", icmp6stat.icp6s_checksum);
+                rrddim_set(st, "InDestUnreachs", icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
+                rrddim_set(st, "InPktTooBigs", icmp6stat.icp6s_badlen);
+                rrddim_set(st, "InTimeExcds", icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
+                rrddim_set(st, "InParmProblems", icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
+                rrddim_set(st, "OutDestUnreachs", icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
+                rrddim_set(st, "OutTimeExcds", icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
+                rrddim_set(st, "OutParmProblems", icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_echos == CONFIG_ONDEMAND_YES || (do_icmp6_echos == CONFIG_ONDEMAND_ONDEMAND && (
+                                                                 icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
+                                                                 icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
+                                                                 icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
+                                                                 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
+                do_icmp6_echos = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmpechos");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InEchos", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutEchos", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InEchos", icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
+                rrddim_set(st, "OutEchos", icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
+                rrddim_set(st, "InEchoReplies", icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
+                rrddim_set(st, "OutEchoReplies", icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_router == CONFIG_ONDEMAND_YES || (do_icmp6_router == CONFIG_ONDEMAND_ONDEMAND && (
+                                                                    icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
+                                                                    icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
+                                                                    icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
+                                                                    icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
+                do_icmp6_router = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmprouter");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
+                rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
+                rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
+                rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_neighbor == CONFIG_ONDEMAND_YES || (do_icmp6_neighbor == CONFIG_ONDEMAND_ONDEMAND && (
+                                                                    icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
+                                                                    icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
+                                                                    icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
+                                                                    icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
+                do_icmp6_neighbor = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmpneighbor");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InSolicits", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutSolicits", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InSolicits", icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
+                rrddim_set(st, "OutSolicits", icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
+                rrddim_set(st, "InAdvertisements", icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
+                rrddim_set(st, "OutAdvertisements", icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            if (do_icmp6_types == CONFIG_ONDEMAND_YES || (do_icmp6_types == CONFIG_ONDEMAND_ONDEMAND && (
+                                                                    icmp6stat.icp6s_inhist[1] ||
+                                                                    icmp6stat.icp6s_inhist[128] ||
+                                                                    icmp6stat.icp6s_inhist[129] ||
+                                                                    icmp6stat.icp6s_inhist[136] ||
+                                                                    icmp6stat.icp6s_outhist[1] ||
+                                                                    icmp6stat.icp6s_outhist[128] ||
+                                                                    icmp6stat.icp6s_outhist[129] ||
+                                                                    icmp6stat.icp6s_outhist[133] ||
+                                                                    icmp6stat.icp6s_outhist[135] ||
+                                                                    icmp6stat.icp6s_outhist[136]))) {
+                do_icmp6_types = CONFIG_ONDEMAND_YES;
+                st = rrdset_find("ipv6.icmptypes");
+                if (unlikely(!st)) {
+                    st = rrdset_create("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
+                                       "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
+
+                    rrddim_add(st, "InType1", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InType128", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InType129", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "InType136", NULL, 1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType1", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType128", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType129", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType133", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType135", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                    rrddim_add(st, "OutType143", NULL, -1, 1, RRDDIM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set(st, "InType1", icmp6stat.icp6s_inhist[1]);
+                rrddim_set(st, "InType128", icmp6stat.icp6s_inhist[128]);
+                rrddim_set(st, "InType129", icmp6stat.icp6s_inhist[129]);
+                rrddim_set(st, "InType136", icmp6stat.icp6s_inhist[136]);
+                rrddim_set(st, "OutType1", icmp6stat.icp6s_outhist[1]);
+                rrddim_set(st, "OutType128", icmp6stat.icp6s_outhist[128]);
+                rrddim_set(st, "OutType129", icmp6stat.icp6s_outhist[129]);
+                rrddim_set(st, "OutType133", icmp6stat.icp6s_outhist[133]);
+                rrddim_set(st, "OutType135", icmp6stat.icp6s_outhist[135]);
+                rrddim_set(st, "OutType143", icmp6stat.icp6s_outhist[143]);
+                rrdset_done(st);
+            }
+        }
+    }
+
     return 0;
 }