]> arthur.barton.de Git - netdata.git/commitdiff
Merge branch 'master' into ab-debian
authorAlexander Barton <alex@barton.de>
Thu, 23 Mar 2017 11:21:24 +0000 (12:21 +0100)
committerAlexander Barton <alex@barton.de>
Thu, 23 Mar 2017 11:21:24 +0000 (12:21 +0100)
* master: (75 commits)
  ipv6 metrics swapped; fixes #2000
  haproxy_plugin: get data via UrlService bugfix
  more info about -W set
  allow all configuration options to be set from the command line; #1991
  allow .scope sub-cgroups
  enable libvirt cgroups
  mongodb_plugin: take "arbiter" replica set member into account
  Create draft release when uploading from Travis
  Update checks to work on OS X
  Post release 1.6.0
  Prepare release 1.6.0
  Fix misc compiler warnings on FreeBSD
  Fix compiler warnings for FreeBSD plugin
  coverity: 164803 Resource leak in ARL (impossible case)
  freebsd coverity: 164808 Uninitialized scalar variable
  freebsd coverity: 164810 Uninitialized scalar variable
  freebsd coverity: 164802 Same on both sides
  fixed typo in sizeof()
  properly initialize new memory regions after reallocz(); fixes #1972
  run-parts does not run scripts with .sh extension
  ...

35 files changed:
.travis.yml
ChangeLog
README.md
conf.d/python.d.conf
configs.signatures
configure.ac
coverity-scan.sh
installer/functions.sh
netdata-installer.sh
netdata.spec.in
packaging/packaging.functions
plugins.d/python.d.plugin
python.d/haproxy.chart.py
python.d/mongodb.chart.py
src/adaptive_resortable_list.c
src/appconfig.c
src/appconfig.h
src/apps_plugin.c
src/backends.c
src/common.c
src/common.h
src/freebsd_sysctl.c
src/global_statistics.c
src/macos_sysctl.c
src/main.c
src/plugin_freebsd.c
src/plugin_freebsd.h
src/plugin_macos.h
src/plugin_nfacct.c
src/proc_net_dev.c
src/proc_net_snmp6.c
src/rrdhost.c
src/sys_fs_cgroup.c
src/web_client.c
system/netdata.service.in

index b7e04bfba79f65ee00d33bcc0c544767941a6c6b..b0e2832e017347d8b448a59c54bc283da3a856e3 100644 (file)
@@ -43,6 +43,7 @@ after_success:
 deploy:
   # Upload results to GitHub (tag only)
   - provider: releases
+    draft: true
     api_key:
       secure: invJ0ZdNOPi9x8JJmFkqSIQMxljkLROwgRFCbmXMausJ0rA4E/PgLtM7ddWrHlu6lu8N9e5Pus4bG8DWATHbY0blMUhL5C82S5KK4mxAANLCLgTV8Qr7dMWnMqRV/OJBMGM1ZWpC2AA5GVhPLF7Z++54iqK+LM8P0EuOTAKbebIWCIkGybbSpXj+jJqaQXY0tLGSn5fXPFfyV3Tw0URJPcO3Uz5iukELngkLVSve2d0XYwy8M5tpLKHJi5bzc9CwcJZ/JK1WvklqmV3fNdSSzZunaAfDwWosV3hO7QcGnAVEbNl0HBKZJ8JkriV2fDbH4fttoSvLO2tW9HauP7Yf5XqLDudqUj4gPTuGzd31vRb9kx9cAulfE9onMAmDbjbne8Cp2Bq9/yBEqaofqEIaRcLgnlZSNc+PWbH4FQJ6fIOs5nfqLJo0G+3isgRWrqxp/rjILOvbIGbfLkbPl9aV09IvzShyW2lK7E+QOP0TZIwyXGT0NW0Rr/eyzuMXooy8wi9NehKfrxIcUr7784nU2E+EtItrhtTkJpK8XBBh16swn7s2sQ89qx9PYd/wE5qnKfG0yy3SSc2ycKzEpH7Cy3E6lC4Jytw0AM1Mc179WASBhlR2tyElkRcuhlqOFlJ/6iXjp3kqSgW4kvWbwHwT6VsyiDRhf+Ir4XILFBJ26Z8=
     skip_cleanup: true
index 2973c89e527853576bcbcee59b4aa1ec779323ca..1f6c5f274823fd598b08f7b0db795d18f7fb536f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,167 @@
+netdata (1.6.0) - 2017-03-20
+
+ * birthday release: 1 year netdata
+
+   netdata was first published on March 30th, 2016.
+   It has been a crazy year since then:
+
+     225.000 unique netdata users
+             currently, at 1.000 new unique users per day
+
+      80.000 unique netdata installations
+             currently, at 500 new installation per day
+
+     610.000 docker pulls on docker hub
+
+   4.000.000 netdata sessions served
+             currently, at 15.000 sessions served per day
+
+      20.000 github stars
+
+             Thank you!
+          You are awesome!
+
+ * central netdata is here
+
+   This is the first release that supports real-time streaming of
+   metrics between netdata servers.
+
+   netdata can now be:
+
+   - autonomous host monitoring
+     (like it always has been)
+
+   - headless data collector
+     (collect and stream metrics in real-time to another netdata)
+
+   - headless proxy
+     (collect metrics from multiple netdata and stream them to another netdata)
+
+   - store and forward proxy
+     (like headless proxy, but with a local database)
+
+   - central database
+     (metrics from multiple hosts are aggregated)
+
+   metrics databases can be configured on all nodes and each node maintaining
+   a database may have a different retention policy and possibly run
+   (even different) alarms on them.
+
+ * monitoring ephemeral nodes
+
+   netdata now supports monitoring autoscaled ephemeral nodes,
+   that are started and stopped on demand (their IP is not known).
+
+   When the ephemeral nodes start streaming metrics to the central
+   netdata, the central netdata will show register them at "my-netdata"
+   menu on the dashboard.
+
+   For more information check:
+   https://github.com/firehol/netdata/wiki/monitoring-ephemeral-nodes
+
+ * monitoring ephemeral containers and VM guests
+
+   netdata now cleans up container, guest VM, network interfaces and mounted
+   disk metrics, disabling automatically their alarms too.
+
+   For more information check:
+   https://github.com/firehol/netdata/wiki/monitoring-ephemeral-containers
+
+ * apps.plugin ported for FreeBSD
+
+   @vlvkobal has ported "apps.plugin" to FreeBSD. netdata can now provide
+   "Applications", "Users" and "User Groups" on FreeBSD.
+
+ * web_log plugin
+
+   @l2isbad has done a wonderful job creating a unified web log parsing plugin
+   for all kinds of web server logs. With it, netdata provides real-time
+   performance information and health monitoring alarms for web applications
+   and web sites!
+
+   For more information check:
+   https://github.com/firehol/netdata/wiki/The-spectacles-of-a-web-server-log-file
+
+ * backends
+
+   netdata can now archive metrics to `JSON` backends
+   (both push, by @lfdominguez, and pull modes).
+
+ * IPMI monitoring
+
+   netdata now has an IPMI plugin (based on freeipmi)
+   for monitoring server hardware.
+
+   The plugin creates (up to) 8 charts:
+
+    1. number of sensors by state
+    2. number of events in SEL
+    3. Temperatures CELCIUS
+    4. Temperatures FAHRENHEIT
+    5. Voltages
+    6. Currents
+    7. Power
+    8. Fans
+
+   It also supports alarms (including the number of sensors in critical state).
+
+   For more information, check:
+   https://github.com/firehol/netdata/wiki/monitoring-IPMI
+
+ * new plugins
+
+   @l2isbad builds python data collection plugins for netdata at an wonderfull
+   rate! He rocks!
+
+    - **web_log** for monitoring in real-time all kinds of web server log files @l2isbad
+    - **freeipmi** for monitoring IPMI (server hardware)
+    - **nsd** (the [name server daemon](https://www.nlnetlabs.nl/projects/nsd/)) @383c57
+    - **mongodb** @l2isbad
+    - **smartd_log** (monitoring disk S.M.A.R.T. values) @l2isbad
+
+ * improved plugins
+
+    - **nfacct** reworked and now collects connection tracker information using netlink.
+    - **ElasticSearch** re-worked @l2isbad
+    - **mysql** re-worked to allow faster development of custom mysql based plugins (MySQLService) @l2isbad
+    - **SNMP**
+    - **tomcat** @NMcCloud
+    - **ap** (monitoring hostapd access points)
+    - **php_fpm** @l2isbad
+    - **postgres** @l2isbad
+    - **isc_dhcpd** @l2isbad
+    - **bind_rndc** @l2isbad
+    - **numa**
+    - **apps.plugin** improvements and freebsd support @vlvkobal
+    - **fail2ban** @l2isbad
+    - **freeradius** @l2isbad
+    - **nut** (monitoring UPSes)
+    - **tc** (Linux QoS) now works on qdiscs instead of classes for the same result (a lot faster) @t-h-e
+    - **varnish** @l2isbad
+
+ * new and improved alarms
+    - **web_log**, many alarms to detect common web site/API issues
+    - **fping**, alarms to detect packet loss, disconnects and unusually high latency
+    - **cpu**, cpu utilization alarm now ignores `nice`
+
+ * new and improved alarm notification methods
+    - **HipChat** to allow hosted HipChat @frei-style
+    - **discordapp** @lowfive
+
+ * dashboard improvements
+    - dashboard now works on HiDPi screens
+    - dashboard now shows version of netdata
+    - dashboard now resets charts properly
+    - dashboard updated to use latest gauge.js release
+
+ * other improvements
+    - thanks to @rlefevre netdata now uses a lot of different high resolution system clocks.
+
+ netdata has received a lot more improvements from many more  contributors!
+
+ Thank you all!
+
+
 netdata (1.5.0) - 2017-01-22
 
  * yet another release that makes netdata the fastest
index 3d73b9ecce452c2a9c340e71990c5014501f133a..cff7f31bde7e3eee0c61c6a298d1cb38a08631c3 100644 (file)
--- a/README.md
+++ b/README.md
@@ -33,15 +33,16 @@ Netdata is featured at <b><a href="https://octoverse.github.com/" target="_blank
 <a href="https://octoverse.github.com/" target="_blank"><img src="https://cloud.githubusercontent.com/assets/2662304/21743260/23ebe62c-d507-11e6-80c0-76b95f53e464.png"/></a>
 </p>
 
-`Jan 22nd, 2017` - **[netdata v1.5.0 released!](https://github.com/firehol/netdata/releases)**
-
- - netdata now runs on **FreeBSD** and **MacOS**
- - netdata now supports **Graphite**, **OpenTSDB**, **Prometheus** and compatible backends
- - netdata now monitors **systemd Services**
- - new plugins: fping, postgres, varnish, elasticsearch, haproxy, freeradius, mdstat, ISC dhcpd, fail2ban, openvpn, NUMA memory, CPU Idle States, gunicorn, ECC memory errors, IPC semaphores, uptime
- - improved plugins: netfilter conntrack, mysql/mariadb, ipfs, cpufreq, hddtemp, sensors, nginx, nginx_log, phpfpm, redis, dovecot, containers and cgroups, disk space, apps.plugin, tc (QoS) and almost all internal plugins (memory, IPv4 and IPv6, network interfaces, QoS, etc)
- - dozens of new and improved alarms (including performance monitoring alarms for mysql)
- - new alarm notifications: messagebird.com, pagerduty.com, pushbullet.com, twilio.com, hipchat, kafka
+`Mar 20th, 2017` - **[netdata v1.6.0 released!](https://github.com/firehol/netdata/releases)**
+
+ - central netdata is here! headless collectors, proxies, streaming of metrics, etc.
+ - [monitoring ephemeral nodes (auto-scaled VMs)](https://github.com/firehol/netdata/wiki/monitoring-ephemeral-nodes)
+ - [monitoring ephemeral containers and VM guests](https://github.com/firehol/netdata/wiki/monitoring-ephemeral-containers)
+ - [monitoring web servers](https://github.com/firehol/netdata/wiki/The-spectacles-of-a-web-server-log-file)
+ - apps.plugin ported for FreeBSD
+ - [monitoring IPMI](https://github.com/firehol/netdata/wiki/monitoring-IPMI)
+ - dozens of new and improved plugins
+ - dozens of new and improved alarms
  - dozens more improvements and performance optimizations
 
 ---
index 96cb4d831f1e58791e0e3e9ecdbf2d26669697a3..9ed346cdcdf76573191a4c12b5c21dce6267bfd6 100644 (file)
@@ -18,9 +18,13 @@ log_interval: 3600
 
 # ----------------------------------------------------------------------
 # Enable / Disable python.d.plugin modules
+#default_run: yes
 #
-# The default for all modules is enabled (yes).
-# Setting any of these to no will disable it.
+# If "default_run" = "yes" the default for all modules is enabled (yes).
+# Setting any of these to "no" will disable it.
+# 
+# If "default_run" = "no" the default for all modules is disabled (no).
+# Setting any of these to "yes" will enable it.
 
 # apache_cache: yes
 # apache: yes
index 593628dac05dcc0e26523ea6a10c41a1563e10b8..713a1d3232f6b2d21895099bc97a781f8fd779b0 100644 (file)
@@ -87,6 +87,7 @@ declare -A configs_signatures=(
   ['373160658e7d5f1a129de397b9347365']='health.d/entropy.conf'
   ['373c1276dc9e65884ff2b26e1f08afe7']='health.d/named.conf'
   ['3798445a7faaf45c7a8047908678e690']='python.d/varnish.conf'
+  ['37bc2b50ade9f334da4775dfea59f785']='python.d.conf'
   ['3848172053221b95279ba9bf789cd4e0']='health.d/apache.conf'
   ['3866efafd38e161136428d0f818cac43']='health.d/net.conf'
   ['38d1bf04fe9901481dd6febcc0404a86']='python.d.conf'
index ddbc28e44fa2736d94eaa473a44fd12f8c9773c4..663f0a395a191049879c1a91ef1e15b5090577c5 100644 (file)
@@ -4,7 +4,7 @@
 AC_PREREQ(2.60)
 
 define([VERSION_MAJOR], [1])
-define([VERSION_MINOR], [5])
+define([VERSION_MINOR], [6])
 define([VERSION_FIX], [1])
 define([VERSION_NUMBER], VERSION_MAJOR[.]VERSION_MINOR[.]VERSION_FIX)
 define([VERSION_SUFFIX], [_rolling])
@@ -55,7 +55,7 @@ AC_ARG_ENABLE(
 )
 AC_ARG_ENABLE(
     [plugin-freeipmi],
-    [AS_HELP_STRING([--enable-plugin-freeipmi], [freeipmi plugin, requires root])],
+    [AS_HELP_STRING([--enable-plugin-freeipmi], [enable freeipmi plugin])],
     ,
     [enable_plugin_freeipmi="detect"]
 )
@@ -363,12 +363,15 @@ AM_CONDITIONAL([ENABLE_PLUGIN_FREEIPMI], [test "${enable_plugin_freeipmi}" = "ye
 # -----------------------------------------------------------------------------
 # nfacct.plugin - libmnl, libnetfilter_acct
 
+AC_CHECK_HEADERS_ONCE([linux/netfilter/nfnetlink_conntrack.h])
+
 PKG_CHECK_MODULES(
     [NFACCT],
     [libnetfilter_acct],
     [have_libnetfilter_acct=yes],
     [have_libnetfilter_acct=no]
 )
+
 PKG_CHECK_MODULES(
     [LIBMNL],
     [libmnl],
@@ -385,6 +388,8 @@ test "${enable_plugin_nfacct}" = "yes" -a "${have_libmnl}" != "yes" && \
 AC_MSG_CHECKING([if nfacct.plugin should be enabled])
 if test "${enable_plugin_nfacct}" != "no" -a "${have_libnetfilter_acct}" = "yes" -a "${have_libmnl}" = "yes"; then
     enable_plugin_nfacct="yes"
+    AC_DEFINE([HAVE_LIBMNL], [1], [libmnl usability])
+    AC_DEFINE([HAVE_LIBNETFILTER_ACCT], [1], [libnetfilter_acct usability])
     AC_DEFINE([INTERNAL_PLUGIN_NFACCT], [1], [nfacct plugin usability])
     OPTIONAL_NFACCT_CLFAGS="${NFACCT_CFLAGS} ${LIBMNL_CFLAGS}"
     OPTIONAL_NFACCT_LIBS="${NFACCT_LIBS} ${LIBMNL_LIBS}"
index c293805a4a49e894b106a8bf78fb2ae20551802a..8ea43345317b3b645924f4dcc052c3675b89f048 100755 (executable)
@@ -18,6 +18,9 @@ covbuild="$(which cov-build 2>/dev/null || command -v cov-build 2>/dev/null)"
        echo "The command ${covbuild} is not executable. Save command the full filename of cov-build in .coverity-build" && \
        exit 1
 
+version="$(cat config.h | grep "^#define PACKAGE_VERSION" | cut -d '"' -f 2)"
+echo >&2 "Working on netdata version: ${version}"
+
 echo >&2 "Cleaning up old builds..."
 make clean || exit 1
 
@@ -34,6 +37,6 @@ tar czvf netdata-coverity-analysis.tgz cov-int || exit 1
 curl --form token="${token}" \
   --form email=costa@tsaousis.gr \
   --form file=@netdata-coverity-analysis.tgz \
-  --form version="1.6.0rc1" \
-  --form description="Description" \
+  --form version="${version}" \
+  --form description="netdata, real-time performance monitoring, done right." \
   https://scan.coverity.com/builds?project=firehol%2Fnetdata
index f27b4535b28284dfd8f968ba1a88832d960d28a1..36d10ec70ad892e066e2d1eba0f7702c1cee37f0 100644 (file)
@@ -17,6 +17,32 @@ check_cmd() {
 # -----------------------------------------------------------------------------
 
 setup_terminal() {
+    TPUT_RESET=""
+    TPUT_BLACK=""
+    TPUT_RED=""
+    TPUT_GREEN=""
+    TPUT_YELLOW=""
+    TPUT_BLUE=""
+    TPUT_PURPLE=""
+    TPUT_CYAN=""
+    TPUT_WHITE=""
+    TPUT_BGBLACK=""
+    TPUT_BGRED=""
+    TPUT_BGGREEN=""
+    TPUT_BGYELLOW=""
+    TPUT_BGBLUE=""
+    TPUT_BGPURPLE=""
+    TPUT_BGCYAN=""
+    TPUT_BGWHITE=""
+    TPUT_BOLD=""
+    TPUT_DIM=""
+    TPUT_UNDERLINED=""
+    TPUT_BLINK=""
+    TPUT_INVERTED=""
+    TPUT_STANDOUT=""
+    TPUT_BELL=""
+    TPUT_CLEAR=""
+
     # Is stderr on the terminal? If not, then fail
     test -t 2 || return 1
 
index d11e96236c8fc1db0bb9b74217ec4b730ec30685..6b672a242e8ad5c04d45a1dfa832e496860e1e33 100755 (executable)
@@ -104,6 +104,12 @@ Valid <installer options> are:
         Enable/disable the FreeIPMI plugin.
         Default: enable it when libipmimonitoring is available.
 
+   --enable-plugin-nfacct
+   --disable-plugin-nfacct
+
+        Enable/disable the nfacct plugin.
+        Default: enable it when libmnl and libnetfilter_acct are available.
+
    --enable-lto
    --disable-lto
 
@@ -205,6 +211,14 @@ do
         then
         NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-plugin-freeipmi"
         shift 1
+    elif [ "$1" = "--enable-plugin-nfacct" ]
+        then
+        NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-plugin-nfacct"
+        shift 1
+    elif [ "$1" = "--disable-plugin-nfacct" ]
+        then
+        NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --disable-plugin-nfacct"
+        shift 1
     elif [ "$1" = "--enable-lto" ]
         then
         NETDATA_CONFIGURE_OPTIONS="${NETDATA_CONFIGURE_OPTIONS} --enable-lto"
@@ -1340,7 +1354,7 @@ if [ -t 2 ]
 else
     # we are headless
     # create a temporary file for the log
-    tmp=\$(mktemp /tmp/netdata-updater-log-XXXXXX.log)
+    tmp=\$(mktemp /tmp/netdata-updater.log.XXXXXX)
     # open fd 3 and send it to tmp
     exec 3>\${tmp}
 fi
@@ -1420,11 +1434,19 @@ REINSTALL
     echo >&2
     echo >&2 "${TPUT_DIM}${TPUT_BOLD}netdata-updater.sh${TPUT_RESET}${TPUT_DIM} can work from cron. It will trigger an email from cron"
     echo >&2 "only if it fails (it does not print anything if it can update netdata).${TPUT_RESET}"
-    if [ "${UID}" -eq 0 -a -d "/etc/cron.daily" -a ! -f "/etc/cron.daily/netdata-updater.sh" ]
-        then
-        echo >&2 "${TPUT_DIM}Run this to automatically check and install netdata updates once per day:${TPUT_RESET}"
-        echo >&2
-        echo >&2 "${TPUT_YELLOW}${TPUT_BOLD}ln -s ${PWD}/netdata-updater.sh /etc/cron.daily/netdata-updater.sh${TPUT_RESET}"
+    if [ "${UID}" -eq "0" ]
+    then
+        if [ -d "/etc/cron.daily" -a ! -f "/etc/cron.daily/netdata-updater.sh" ]
+            then
+            echo >&2 "${TPUT_DIM}Run this to automatically check and install netdata updates once per day:${TPUT_RESET}"
+            echo >&2
+            echo >&2 "${TPUT_YELLOW}${TPUT_BOLD}ln -s ${PWD}/netdata-updater.sh /etc/cron.daily/netdata-updater.sh${TPUT_RESET}"
+        elif [ -d "/etc/periodic/daily" -a ! -f "/etc/periodic/daily/netdata-updater" ]
+            then
+            echo >&2 "${TPUT_DIM}Run this to automatically check and install netdata updates once per day:${TPUT_RESET}"
+            echo >&2
+            echo >&2 "${TPUT_YELLOW}${TPUT_BOLD}ln -s ${PWD}/netdata-updater.sh /etc/periodic/daily/netdata-updater${TPUT_RESET}"
+        fi
     fi
 elif [ -f "netdata-updater.sh" ]
     then
index b1f0189e03c147775b29a2530c8763b778380424..685d6e0e790292c829b5f76fe968abac0f97fe53 100644 (file)
@@ -205,6 +205,17 @@ rm -rf "${RPM_BUILD_ROOT}"
 %{_datadir}/%{name}/web
 
 %changelog
+* Mon Mar 20 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.6.0-1
+- central netdata
+- monitoring ephemeral nodes
+- monitoring ephemeral containers and VM guests
+- apps.plugin ported for FreeBSD
+- web_log plugin
+- JSON backends
+- IPMI monitoring
+- several new and improved plugins
+- several new and improved alarms and notifications
+- dozens more improvements and bug fixes
 * Sun Jan 22 2017 Costa Tsaousis <costa@tsaousis.gr> - 1.5.0-1
 - FreeBSD, MacOS, FreeNAS
 - Backends support
index d74fbfeac2597ae3908655c1e36990157028c1fb..c18c8fe1842c72ba7bdfef9ad230305e00c48c37 100644 (file)
@@ -128,7 +128,7 @@ get_configure_ac_rpmrel() {
 get_spec_version() {
   get_staged_file -o "$1".spec.in
   test -f $MYTMP/files/"$1".spec.in || return 0 # Spec file is optional
-  sed -n -e '1,/^%changelog/d' -e '/^*/{s/.*- \([0-9].*\)/\1/p;q}' "$1".spec.in
+  sed -n -e '1,/^%changelog/d' -e '/^*/{' -e 's/.*- \([0-9].*\)/\1/p' -e q -e '}' "$1".spec.in
 }
 
 splitver() {
index 4fdfae34725fb18d0f715ac07c8065fa877cd4ee..efa62cbc5a34affbd86651147a50e08871ff7e0f 100755 (executable)
@@ -86,14 +86,16 @@ if ORDERED:
     def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
         class OrderedLoader(Loader):
             pass
+
         def construct_mapping(loader, node):
-           loader.flatten_mapping(node)
-           return object_pairs_hook(loader.construct_pairs(node))
+            loader.flatten_mapping(node)
+            return object_pairs_hook(loader.construct_pairs(node))
         OrderedLoader.add_constructor(
             yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
             construct_mapping)
         return yaml.load(stream, OrderedLoader)
 
+
 class PythonCharts(object):
     """
     Main class used to control every python module.
@@ -103,12 +105,16 @@ class PythonCharts(object):
                  modules=None,
                  modules_path='../python.d/',
                  modules_configs='../conf.d/',
-                 modules_disabled=None):
+                 modules_disabled=None,
+                 modules_enabled=None,
+                 default_run=None):
         """
         :param modules: list
         :param modules_path: str
         :param modules_configs: str
         :param modules_disabled: list
+        :param modules_enabled: list
+        :param default_run: bool
         """
 
         if modules is None:
@@ -121,13 +127,13 @@ class PythonCharts(object):
         self.configs = modules_configs
 
         # load modules
-        loaded_modules = self._load_modules(modules_path, modules, modules_disabled)
+        loaded_modules = self._load_modules(modules_path, modules, modules_disabled, modules_enabled, default_run)
 
         # load configuration files
         configured_modules = self._load_configs(loaded_modules)
 
         # good economy and prosperity:
-        self.jobs = self._create_jobs(configured_modules)  # type: list
+        self.jobs = self._create_jobs(configured_modules)  # type <list>
 
         # enable timetable override like `python.d.plugin mysql debug 1`
         if DEBUG_FLAG and OVERRIDE_UPDATE_EVERY:
@@ -157,7 +163,7 @@ class PythonCharts(object):
             msg.error("Problem loading", name, str(e))
             return None
 
-    def _load_modules(self, path, modules, disabled):
+    def _load_modules(self, path, modules, disabled, enabled, default_run):
         """
         Load modules from 'modules' list or dynamically every file from 'path' (only .chart.py files)
         :param path: str
@@ -183,7 +189,10 @@ class PythonCharts(object):
                     msg.fatal('no modules found.')
         else:
             # scan directory specified in path and load all modules from there
-            names = os.listdir(path)
+            if default_run is False:
+                names = [module for module in os.listdir(path) if module[:-9] in enabled]
+            else:
+                names = os.listdir(path)
             for mod in names:
                 if mod.replace(MODULE_EXTENSION, "") in disabled:
                     msg.error(mod + ": disabled module ", mod.replace(MODULE_EXTENSION, ""))
@@ -369,7 +378,8 @@ class PythonCharts(object):
                         if job.override_name is not None:
                             new_name = job.__module__ + '_' + sub(r'\s+', '_', job.override_name)
                             if new_name in overridden:
-                                msg.info("DROPPED:", job.name, ", job '" + job.override_name + "' is already served by another job.")
+                                msg.info("DROPPED:", job.name, ", job '" + job.override_name +
+                                         "' is already served by another job.")
                                 self._stop(job)
                                 i -= 1
                             else:
@@ -481,7 +491,7 @@ def parse_cmdline(directory, *commands):
         elif cmd == "trace" or cmd == "all":
             TRACE_FLAG = True
         elif os.path.isfile(directory + cmd + ".chart.py") or os.path.isfile(directory + cmd):
-            #DEBUG_FLAG = True
+            # DEBUG_FLAG = True
             mods.append(cmd.replace(".chart.py", ""))
         else:
             try:
@@ -507,6 +517,8 @@ def run():
 
     # read configuration file
     disabled = ['nginx_log', 'gunicorn_log']
+    enabled = list()
+    default_run = True
     configfile = CONFIG_DIR + "python.d.conf"
     msg.PROGRAM = PROGRAM
     msg.info("reading configuration file:", configfile)
@@ -548,12 +560,17 @@ def run():
         except (KeyError, TypeError):
             pass
 
+        default_run = True if ('default_run' not in conf or conf.get('default_run')) else False
+
         for k, v in conf.items():
-            if k in ("update_every", "debug", "enabled"):
+            if k in ("update_every", "debug", "enabled", "default_run"):
                 continue
-            if v is False:
-                disabled.append(k)
-
+            if default_run:
+                if v is False:
+                    disabled.append(k)
+            else:
+                if v is True:
+                    enabled.append(k)
     # parse passed command line arguments
     modules = parse_cmdline(MODULES_DIR, *sys.argv)
     msg.DEBUG_FLAG = DEBUG_FLAG
@@ -568,7 +585,7 @@ def run():
              ", ONLY_MODULES=" + str(modules))
 
     # run plugins
-    charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled)
+    charts = PythonCharts(modules, MODULES_DIR, CONFIG_DIR + "python.d/", disabled, enabled, default_run)
     charts.check()
     charts.create()
     charts.update()
index 2fb97d755bab93e5132e66d92a9fa4361202f770..779e060a95ba1c9ffc72d35ec69668fa57c58b15 100644 (file)
@@ -13,43 +13,44 @@ retries = 60
 ORDER = ['fbin', 'fbout', 'fscur', 'fqcur', 'bbin', 'bbout', 'bscur', 'bqcur', 'health_sdown', 'health_bdown']
 CHARTS = {
     'fbin': {
-        'options': [None, "Kilobytes in", "kilobytes in/s", 'Frontend', 'haproxy_f.bin', 'line'],
+        'options': [None, "Kilobytes In", "KB/s", 'frontend', 'haproxy_f.bin', 'line'],
         'lines': [
         ]},
     'fbout': {
-        'options': [None, "Kilobytes out", "kilobytes out/s", 'Frontend', 'haproxy_f.bout', 'line'],
+        'options': [None, "Kilobytes Out", "KB/s", 'frontend', 'haproxy_f.bout', 'line'],
         'lines': [
         ]},
     'fscur': {
-        'options': [None, "Sessions active", "sessions", 'Frontend', 'haproxy_f.scur', 'line'],
+        'options': [None, "Sessions Active", "sessions", 'frontend', 'haproxy_f.scur', 'line'],
         'lines': [
         ]},
     'fqcur': {
-        'options': [None, "Session in queue", "sessions", 'Frontend', 'haproxy_f.qcur', 'line'],
+        'options': [None, "Session In Queue", "sessions", 'frontend', 'haproxy_f.qcur', 'line'],
         'lines': [
         ]},
     'bbin': {
-        'options': [None, "Kilobytes in", "kilobytes in/s", 'Backend', 'haproxy_b.bin', 'line'],
+        'options': [None, "Kilobytes In", "KB/s", 'backend', 'haproxy_b.bin', 'line'],
         'lines': [
         ]},
     'bbout': {
-        'options': [None, "Kilobytes out", "kilobytes out/s", 'Backend', 'haproxy_b.bout', 'line'],
+        'options': [None, "Kilobytes Out", "KB/s", 'backend', 'haproxy_b.bout', 'line'],
         'lines': [
         ]},
     'bscur': {
-        'options': [None, "Sessions active", "sessions", 'Backend', 'haproxy_b.scur', 'line'],
+        'options': [None, "Sessions Active", "sessions", 'backend', 'haproxy_b.scur', 'line'],
         'lines': [
         ]},
     'bqcur': {
-        'options': [None, "Sessions in queue", "sessions", 'Backend', 'haproxy_b.qcur', 'line'],
+        'options': [None, "Sessions In Queue", "sessions", 'backend', 'haproxy_b.qcur', 'line'],
         'lines': [
         ]},
     'health_sdown': {
-        'options': [None, "Number of servers in backend in DOWN state", "failed servers", 'Health', 'haproxy_hs.down', 'line'],
+        'options': [None, "Backend Servers In DOWN State", "failed servers", 'health',
+                    'haproxy_hs.down', 'line'],
         'lines': [
         ]},
     'health_bdown': {
-        'options': [None, "Is backend alive? 1 = DOWN", "failed backend", 'Health', 'haproxy_hb.down', 'line'],
+        'options': [None, "Is backend alive? 1 = DOWN", "failed backend", 'health', 'haproxy_hb.down', 'line'],
         'lines': [
         ]}
 }
@@ -57,61 +58,68 @@ CHARTS = {
 
 class Service(UrlService, SocketService):
     def __init__(self, configuration=None, name=None):
-        SocketService.__init__(self, configuration=configuration, name=name)
-        self.user = self.configuration.get('user')
-        self.password = self.configuration.get('pass')
-        self.request = 'show stat\n'
-        self.poll_method = (UrlService, SocketService)
+        if 'socket' in configuration:
+            SocketService.__init__(self, configuration=configuration, name=name)
+            self.poll_method = SocketService
+            self.request = 'show stat\n'
+        else:
+            UrlService.__init__(self, configuration=configuration, name=name)
+            self.poll_method = UrlService
         self.order = ORDER
+        self.definitions = CHARTS
         self.order_front = [_ for _ in ORDER if _.startswith('f')]
         self.order_back = [_ for _ in ORDER if _.startswith('b')]
-        self.definitions = CHARTS
         self.charts = True
 
     def check(self):
-        if self.configuration.get('url'):
-            self.poll_method = self.poll_method[0]
-            url = self.configuration.get('url')
-            if not url.endswith(';csv;norefresh'):
-                self.error('Bad url(%s). Must be http://<ip.address>:<port>/<url>;csv;norefresh' % url)
-                return False
-        elif self.configuration.get('socket'):
-            self.poll_method = self.poll_method[1]
-        else:
-            self.error('No configuration is specified')
-            return False
 
         if self.poll_method.check(self):
-            self.info('Plugin was started succesfully. We are using %s.' % self.poll_method.__name__)
+            self.info('Plugin was started successfully. We are using %s.' % self.poll_method.__name__)
             return True
+        else:
+            return False
 
     def create_charts(self, front_ends, back_ends):
-        for _ in range(len(front_ends)):
-            self.definitions['fbin']['lines'].append(['_'.join(['fbin', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'incremental', 1, 1024])
-            self.definitions['fbout']['lines'].append(['_'.join(['fbout', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'incremental', 1, 1024])
-            self.definitions['fscur']['lines'].append(['_'.join(['fscur', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'absolute'])
-            self.definitions['fqcur']['lines'].append(['_'.join(['fqcur', front_ends[_]['# pxname']]), front_ends[_]['# pxname'], 'absolute'])
-        
-        for _ in range(len(back_ends)):
-            self.definitions['bbin']['lines'].append(['_'.join(['bbin', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'incremental', 1, 1024])
-            self.definitions['bbout']['lines'].append(['_'.join(['bbout', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'incremental', 1, 1024])
-            self.definitions['bscur']['lines'].append(['_'.join(['bscur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
-            self.definitions['bqcur']['lines'].append(['_'.join(['bqcur', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
-            self.definitions['health_sdown']['lines'].append(['_'.join(['hsdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
-            self.definitions['health_bdown']['lines'].append(['_'.join(['hbdown', back_ends[_]['# pxname']]), back_ends[_]['# pxname'], 'absolute'])
-                
+        for _ in enumerate(front_ends):
+            idx = _[0]
+            self.definitions['fbin']['lines'].append(['_'.join(['fbin', front_ends[idx]['# pxname']]),
+                                                      front_ends[idx]['# pxname'], 'incremental', 1, 1024])
+            self.definitions['fbout']['lines'].append(['_'.join(['fbout', front_ends[idx]['# pxname']]),
+                                                       front_ends[idx]['# pxname'], 'incremental', 1, 1024])
+            self.definitions['fscur']['lines'].append(['_'.join(['fscur', front_ends[idx]['# pxname']]),
+                                                       front_ends[idx]['# pxname'], 'absolute'])
+            self.definitions['fqcur']['lines'].append(['_'.join(['fqcur', front_ends[idx]['# pxname']]),
+                                                       front_ends[idx]['# pxname'], 'absolute'])
+
+        for _ in enumerate(back_ends):
+            idx = _[0]
+            self.definitions['bbin']['lines'].append(['_'.join(['bbin', back_ends[idx]['# pxname']]),
+                                                      back_ends[idx]['# pxname'], 'incremental', 1, 1024])
+            self.definitions['bbout']['lines'].append(['_'.join(['bbout', back_ends[idx]['# pxname']]),
+                                                       back_ends[idx]['# pxname'], 'incremental', 1, 1024])
+            self.definitions['bscur']['lines'].append(['_'.join(['bscur', back_ends[idx]['# pxname']]),
+                                                       back_ends[idx]['# pxname'], 'absolute'])
+            self.definitions['bqcur']['lines'].append(['_'.join(['bqcur', back_ends[idx]['# pxname']]),
+                                                       back_ends[idx]['# pxname'], 'absolute'])
+            self.definitions['health_sdown']['lines'].append(['_'.join(['hsdown', back_ends[idx]['# pxname']]),
+                                                              back_ends[idx]['# pxname'], 'absolute'])
+            self.definitions['health_bdown']['lines'].append(['_'.join(['hbdown', back_ends[idx]['# pxname']]),
+                                                              back_ends[idx]['# pxname'], 'absolute'])
+
     def _get_data(self):
         """
         Format data received from http request
         :return: dict
         """
-        try:
-            raw_data = self.poll_method._get_raw_data(self).splitlines()
-        except Exception as e:
-            self.error(str(e))
+        raw_data = self.poll_method._get_raw_data(self)
+
+        if not raw_data:
             return None
+        else:
+            raw_data = raw_data.splitlines()
 
-        all_instances = [dict(zip(raw_data[0].split(','), raw_data[_].split(','))) for _ in range(1, len(raw_data))]
+        all_instances = [dict(zip(raw_data[0].split(','),
+                                  raw_data[_].split(','))) for _ in range(1, len(raw_data))]
 
         back_ends = list(filter(is_backend, all_instances))
         front_ends = list(filter(is_frontend, all_instances))
@@ -124,21 +132,26 @@ class Service(UrlService, SocketService):
         to_netdata = dict()
 
         for frontend in front_ends:
-            for _ in self.order_front:
-                to_netdata.update({'_'.join([_, frontend['# pxname']]): int(frontend[_[1:]]) if frontend.get(_[1:]) else 0})
+            for idx in self.order_front:
+                to_netdata.update({'_'.join([idx, frontend['# pxname']]):
+                                   int(frontend[idx[1:]]) if frontend.get(idx[1:]) else 0})
 
         for backend in back_ends:
-            for _ in self.order_back:
-                to_netdata.update({'_'.join([_, backend['# pxname']]): int(backend[_[1:]]) if backend.get(_[1:]) else 0})
+            for idx in self.order_back:
+                to_netdata.update({'_'.join([idx, backend['# pxname']]):
+                                   int(backend[idx[1:]]) if backend.get(idx[1:]) else 0})
 
-        for _ in range(len(back_ends)):
-            to_netdata.update({'_'.join(['hsdown', back_ends[_]['# pxname']]):
-                           len([server for server in servers if is_server_down(server, back_ends, _)])})
-            to_netdata.update({'_'.join(['hbdown', back_ends[_]['# pxname']]): 1 if is_backend_down(back_ends, _) else 0})
+        for _ in enumerate(back_ends):
+            idx = _[0]
+            to_netdata.update({'_'.join(['hsdown', back_ends[idx]['# pxname']]):
+                               len([server for server in servers if is_server_down(server, back_ends, idx)])})
+            to_netdata.update({'_'.join(['hbdown', back_ends[idx]['# pxname']]):
+                               1 if is_backend_down(back_ends, idx) else 0})
 
         return to_netdata
 
-    def _check_raw_data(self, data):
+    @staticmethod
+    def _check_raw_data(data):
         """
         Check if all data has been gathered from socket
         :param data: str
@@ -146,32 +159,22 @@ class Service(UrlService, SocketService):
         """
         return not bool(data)
 
+
 def is_backend(backend):
-    try:
-        return backend['svname'] == 'BACKEND' and backend['# pxname'] != 'stats'
-    except Exception:
-        return False
+        return backend.get('svname') == 'BACKEND' and backend.get('# pxname') != 'stats'
+
 
 def is_frontend(frontend):
-    try:
-        return frontend['svname'] == 'FRONTEND' and frontend['# pxname'] != 'stats'
-    except Exception:
-        return False
+        return frontend.get('svname') == 'FRONTEND' and frontend.get('# pxname') != 'stats'
+
 
 def is_server(server):
-    try:
-        return not server['svname'].startswith(('FRONTEND', 'BACKEND'))
-    except Exception:
-        return False
-
-def is_server_down(server, back_ends, _):
-    try:
-        return server['# pxname'] == back_ends[_]['# pxname'] and server['status'] == 'DOWN'
-    except Exception:
-        return False
-
-def is_backend_down(back_ends, _):
-    try:
-        return back_ends[_]['status'] == 'DOWN'
-    except Exception:
-        return False
+        return not server.get('svname', '').startswith(('FRONTEND', 'BACKEND'))
+
+
+def is_server_down(server, back_ends, idx):
+    return server.get('# pxname') == back_ends[idx].get('# pxname') and server.get('status') == 'DOWN'
+
+
+def is_backend_down(back_ends, idx):
+    return back_ends[idx].get('status') == 'DOWN'
index c01bd293c29ff709bbb9cb9b12ef79a91114d375..953f025ebb6f1c6c936d4deb7a0a0296130697da 100644 (file)
@@ -391,13 +391,18 @@ class Service(SimpleService):
         self.build_metrics_to_collect_(server_status)
 
         try:
-            self._get_data()
+            data = self._get_data()
         except (LookupError, SyntaxError, AttributeError):
             self.error('Type: %s, error: %s' % (str(exc_info()[0]), str(exc_info()[1])))
             return False
         else:
-            self.create_charts_(server_status)
-            return True
+            if isinstance(data, dict) and data:
+                self._data_from_check = data
+                self.create_charts_(server_status)
+                return True
+            else:
+                self.error('_get_data() returned no data or type is not <dict>')
+                return False
 
     def build_metrics_to_collect_(self, server_status):
 
@@ -473,7 +478,7 @@ class Service(SimpleService):
                     lines.append([dim_id, description, 'absolute', 1, 1])
                 return lines
 
-            all_hosts = server_status['repl']['hosts']
+            all_hosts = server_status['repl']['hosts'] + server_status['repl'].get('arbiters', list())
             this_host = server_status['repl']['me']
             other_hosts = [host for host in all_hosts if host != this_host]
 
@@ -620,7 +625,7 @@ class Service(SimpleService):
                 if not member.get('self'):
                     other_hosts.append(member)
                 # Replica set time diff between current time and time when last entry from the oplog was applied
-                if member['optimeDate'] != unix_epoch:
+                if member.get('optimeDate', unix_epoch) != unix_epoch:
                     member_optimedate = member['name'] + '_optimedate'
                     to_netdata.update({member_optimedate: int(delta_calculation(delta=utc_now - member['optimeDate'],
                                                                                 multiplier=1000))})
index 7ae8ba1459f2c0eef7d64c0e7cd2aa14674c1cf0..f74c53eae5e192845ae57ed7975eb3ee9d8d5034 100644 (file)
@@ -233,9 +233,14 @@ int arl_find_or_create_and_relink(ARL_BASE *base, const char *s, const char *val
         if(base->head == base->next_keyword)
             base->head = e;
     }
-    else
+    else {
         e->prev = NULL;
 
+        if(!base->head)
+            base->head = e;
+    }
+
+    // prepare the next iteration
     base->next_keyword = e->next;
     if(unlikely(!base->next_keyword))
         base->next_keyword = base->head;
index 71ff4b75e255a36977685aa049e6d28d43da7691..ae92ad0454a16444aeff44443913e6d79c5a5dfa 100644 (file)
@@ -337,7 +337,7 @@ const char *appconfig_set_default(struct config *root, const char *section, cons
 {
     struct config_option *cv;
 
-    debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
+    debug(D_CONFIG, "request to set default config in section '%s', name '%s', value '%s'", section, name, value);
 
     struct section *co = appconfig_section_find(root, section);
     if(!co) return appconfig_set(root, section, name, value);
@@ -558,7 +558,7 @@ void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
                 if(only_changed && !changed) continue;
 
                 if(!used) {
-                    buffer_sprintf(wb, "\n# node '%s' is not used.", co->name);
+                    buffer_sprintf(wb, "\n# section '%s' is not used.", co->name);
                 }
 
                 buffer_sprintf(wb, "\n[%s]\n", co->name);
index 45cc8cfd5215d18303abbb407091a58998db3379..81db5d9739882749bac7410cf378bfef154bc507 100644 (file)
@@ -56,7 +56,7 @@ extern void appconfig_generate(struct config *root, BUFFER *wb, int only_changed
 #define config_get_boolean(section, name, value) appconfig_get_boolean(&netdata_config, section, name, value)
 #define config_get_boolean_ondemand(section, name, value) appconfig_get_boolean_ondemand(&netdata_config, section, name, value)
 
-#define config_set(section, name, default_value) appconfig_get(&netdata_config, section, name, default_value)
+#define config_set(section, name, default_value) appconfig_set(&netdata_config, section, name, default_value)
 #define config_set_default(section, name, value) appconfig_set_default(&netdata_config, section, name, value)
 #define config_set_number(section, name, value) appconfig_set_number(&netdata_config, section, name, value)
 #define config_set_boolean(section, name, value) appconfig_set_boolean(&netdata_config, section, name, value)
index bea06c3c84030d07cf2c2260bb6ca2c4df678d10..b1bf06bee9dc2aee1a3d100b5c86a1e0571e9a4e 100644 (file)
@@ -1080,6 +1080,7 @@ static inline int read_proc_pid_statm(struct pid_stat *p, void *ptr) {
 
     return 1;
 
+#ifndef __FreeBSD__
 cleanup:
     p->statm_size           = 0;
     p->statm_resident       = 0;
@@ -1089,6 +1090,7 @@ cleanup:
     // p->statm_data           = 0;
     // p->statm_dirty          = 0;
     return 0;
+#endif
 }
 
 static inline int read_proc_pid_io(struct pid_stat *p, void *ptr) {
@@ -1142,6 +1144,7 @@ static inline int read_proc_pid_io(struct pid_stat *p, void *ptr) {
 
     return 1;
 
+#ifndef __FreeBSD__
 cleanup:
     p->io_logical_bytes_read        = 0;
     p->io_logical_bytes_written     = 0;
@@ -1151,23 +1154,24 @@ cleanup:
     p->io_storage_bytes_written     = 0;
     // p->io_cancelled_write_bytes  = 0;
     return 0;
+#endif
 }
 
 static inline int read_proc_stat() {
 #ifdef __FreeBSD__
     long cp_time[CPUSTATES];
-    int i;
+    static kernel_uint_t utime_raw = 0, stime_raw = 0, ntime_raw = 0;
 
     if (unlikely(CPUSTATES != 5)) {
         error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
         goto cleanup;
     }
-    if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) goto cleanup;
+    if (unlikely(GETSYSCTL_BY_NAME("kern.cp_time", cp_time))) goto cleanup;
 #else
     static char filename[FILENAME_MAX + 1] = "";
     static procfile *ff = NULL;
-#endif
     static kernel_uint_t utime_raw = 0, stime_raw = 0, gtime_raw = 0, gntime_raw = 0, ntime_raw = 0;
+#endif
     static usec_t collected_usec = 0, last_collected_usec = 0;
 
 #ifndef __FreeBSD__
@@ -2000,6 +2004,7 @@ static inline void link_all_processes_to_their_parents(void) {
 // to avoid filling up all disk space
 // if debug is enabled, all errors are printed
 
+#ifndef __FreeBSD__
 static int compar_pid(const void *pid1, const void *pid2) {
 
     struct pid_stat *p1 = all_pids[*((pid_t *)pid1)];
@@ -2010,6 +2015,7 @@ static int compar_pid(const void *pid1, const void *pid2) {
     else
         return 1;
 }
+#endif
 
 static inline int collect_data_for_pid(pid_t pid, void *ptr) {
     if(unlikely(pid < INIT_PID || pid > pid_max)) {
@@ -2096,7 +2102,9 @@ static int collect_data_for_all_processes(void) {
 #endif
 
     if(all_pids_count) {
+#ifndef __FreeBSD__
         size_t slc = 0;
+#endif
         for(p = root_of_pids; p ; p = p->next) {
             p->read             = 0; // mark it as not read, so that collect_data_for_pid() will read it
             p->updated          = 0;
index d30deef086f4322c6a110198839ff0988e421911..3e385cab504bb46a91f1369d444986922baffa84 100644 (file)
@@ -286,9 +286,9 @@ static inline int format_dimension_collected_json_plaintext(
 
         "\"chart_id\":\"%s\","
         "\"chart_name\":\"%s\","
-        "\"family\":\"%s\","
-        "\"context\": \"%s\","
-        "\"type\":\"%s\","
+        "\"chart_family\":\"%s\","
+        "\"chart_context\": \"%s\","
+        "\"chart_type\":\"%s\","
         "\"units\": \"%s\","
 
         "\"id\":\"%s\","
@@ -338,9 +338,9 @@ static inline int format_dimension_stored_json_plaintext(
 
             "\"chart_id\":\"%s\","
             "\"chart_name\":\"%s\","
-            "\"family\":\"%s\","
-            "\"context\": \"%s\","
-            "\"type\":\"%s\","
+            "\"chart_family\":\"%s\","
+            "\"chart_context\": \"%s\","
+            "\"chart_type\":\"%s\","
             "\"units\": \"%s\","
 
             "\"id\":\"%s\","
index e46397c624be004daa578e0539563b90bd5985e8..88fcf85bc2a981ec35270db4f7281118d46052fc 100644 (file)
@@ -914,6 +914,9 @@ char *trim(char *s) {
 }
 
 void *mymmap(const char *filename, size_t size, int flags, int ksm) {
+#ifndef MADV_MERGEABLE
+    (void)ksm;
+#endif
     static int log_madvise_1 = 1;
 #ifdef MADV_MERGEABLE
     static int log_madvise_2 = 1, log_madvise_3 = 1;
@@ -1104,7 +1107,7 @@ long get_system_cpus(void) {
     #ifdef __APPLE__
         int32_t tmp_processors;
 
-        if (unlikely(GETSYSCTL("hw.logicalcpu", tmp_processors))) {
+        if (unlikely(GETSYSCTL_BY_NAME("hw.logicalcpu", tmp_processors))) {
             error("Assuming system has %d processors.", processors);
         } else {
             processors = tmp_processors;
@@ -1114,7 +1117,7 @@ long get_system_cpus(void) {
     #elif __FreeBSD__
         int32_t tmp_processors;
 
-        if (unlikely(GETSYSCTL("hw.ncpu", tmp_processors))) {
+        if (unlikely(GETSYSCTL_BY_NAME("hw.ncpu", tmp_processors))) {
             error("Assuming system has %d processors.", processors);
         } else {
             processors = tmp_processors;
@@ -1166,7 +1169,7 @@ pid_t get_system_pid_max(void) {
     #elif __FreeBSD__
         int32_t tmp_pid_max;
 
-        if (unlikely(GETSYSCTL("kern.pid_max", tmp_pid_max))) {
+        if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
             pid_max = 99999;
             error("Assuming system's maximum pid is %d.", pid_max);
         } else {
index f2c764b53495389e6e17752c3e82261281b0a7df..b82c078fa3552fe8f0ea5072fc0d679733e54982 100644 (file)
 #include "plugin_nfacct.h"
 
 #if defined(__FreeBSD__)
+#include <pthread_np.h>
 #include "plugin_freebsd.h"
 #define NETDATA_OS_TYPE "freebsd"
 #elif defined(__APPLE__)
index 1dc9d47bbfd6b639b05fee9bd0fd19e21ed8a206..965c1cbbfd50523b324b6f8267bfa44848fe0d7d 100644 (file)
@@ -1,42 +1,33 @@
 #include "common.h"
 
-// NEEDED BY: struct vmtotal, struct vmmeter
 #include <sys/vmmeter.h>
-// NEEDED BY: struct devstat
 #include <sys/devicestat.h>
-// NEEDED BY: struct xswdev
+#include <sys/mount.h>
 #include <vm/vm_param.h>
-// NEEDED BY: struct semid_kernel, struct shmid_kernel, struct msqid_kernel
+
 #define _KERNEL
 #include <sys/sem.h>
 #include <sys/shm.h>
 #include <sys/msg.h>
 #undef _KERNEL
-// NEEDED BY: struct sysctl_netisr_workstream, struct sysctl_netisr_work
+
 #include <net/netisr.h>
-// NEEDED BY: struct ifaddrs, getifaddrs()
 #include <net/if.h>
 #include <ifaddrs.h>
-// NEEDED BY do_tcp...
-#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_var.h>
 #include <netinet/ip_icmp.h>
 #include <netinet/icmp_var.h>
-// NEEDED BY do_ip6...
 #include <netinet6/ip6_var.h>
-// NEEDED BY do_icmp6...
 #include <netinet/icmp6.h>
-// NEEDED BY do_space, do_inodes
-#include <sys/mount.h>
-// NEEDED BY do_uptime
-#include <time.h>
+#include <netinet/tcp_var.h>
+#include <netinet/tcp_fsm.h>
+#include <netinet/udp.h>
+#include <netinet/udp_var.h>
+
+// --------------------------------------------------------------------------------------------------------------------
+// common definitions and variables
 
 #define KILO_FACTOR 1024
 #define MEGA_FACTOR 1048576     // 1024 * 1024
 
 #define MAX_INT_DIGITS 10 // maximum number of digits for int
 
-// NEEDED BY: do_disk_io
-#define RRD_TYPE_DISK "disk"
+int system_pagesize = PAGE_SIZE;
+int number_of_cpus = 1;
 
-// FreeBSD calculates load averages once every 5 seconds
-#define MIN_LOADAVG_UPDATE_EVERY 5
+// --------------------------------------------------------------------------------------------------------------------
+// FreeBSD plugin initialization
 
-// NEEDED BY: do_bandwidth
-#define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
-
-int do_freebsd_sysctl(int update_every, usec_t dt) {
-    static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1,
-        do_loadavg = -1, do_all_processes = -1, do_disk_io = -1, do_swap = -1, do_ram = -1, do_swapio = -1,
-        do_pgfaults = -1, do_committed = -1, do_ipc_semaphores = -1, do_ipc_shared_mem = -1, do_ipc_msg_queues = -1,
-        do_dev_intr = -1, do_soft_intr = -1, do_netisr = -1, do_netisr_per_core = -1, do_bandwidth = -1,
-        do_tcp_sockets = -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, do_space = -1, do_inodes = -1, do_uptime = -1;
-
-    if (unlikely(do_cpu == -1)) {
-        do_cpu                  = config_get_boolean("plugin:freebsd:sysctl", "cpu utilization", 1);
-        do_cpu_cores            = config_get_boolean("plugin:freebsd:sysctl", "per cpu core utilization", 1);
-        do_interrupts           = config_get_boolean("plugin:freebsd:sysctl", "cpu interrupts", 1);
-        do_dev_intr             = config_get_boolean("plugin:freebsd:sysctl", "device interrupts", 1);
-        do_soft_intr            = config_get_boolean("plugin:freebsd:sysctl", "software interrupts", 1);
-        do_context              = config_get_boolean("plugin:freebsd:sysctl", "context switches", 1);
-        do_forks                = config_get_boolean("plugin:freebsd:sysctl", "processes started", 1);
-        do_processes            = config_get_boolean("plugin:freebsd:sysctl", "processes running", 1);
-        do_loadavg              = config_get_boolean("plugin:freebsd:sysctl", "enable load average", 1);
-        do_all_processes        = config_get_boolean("plugin:freebsd:sysctl", "enable total processes", 1);
-        do_disk_io              = config_get_boolean("plugin:freebsd:sysctl", "stats for all disks", 1);
-        do_swap                 = config_get_boolean("plugin:freebsd:sysctl", "system swap", 1);
-        do_ram                  = config_get_boolean("plugin:freebsd:sysctl", "system ram", 1);
-        do_swapio               = config_get_boolean("plugin:freebsd:sysctl", "swap i/o", 1);
-        do_pgfaults             = config_get_boolean("plugin:freebsd:sysctl", "memory page faults", 1);
-        do_committed            = config_get_boolean("plugin:freebsd:sysctl", "committed memory", 1);
-        do_ipc_semaphores       = config_get_boolean("plugin:freebsd:sysctl", "ipc semaphores", 1);
-        do_ipc_shared_mem       = config_get_boolean("plugin:freebsd:sysctl", "ipc shared memory", 1);
-        do_ipc_msg_queues       = config_get_boolean("plugin:freebsd:sysctl", "ipc message queues", 1);
-        do_netisr               = config_get_boolean("plugin:freebsd:sysctl", "netisr", 1);
-        do_netisr_per_core      = config_get_boolean("plugin:freebsd:sysctl", "netisr per core", 1);
-        do_bandwidth            = config_get_boolean("plugin:freebsd:sysctl", "bandwidth", 1);
-        do_tcp_sockets          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP connections", 1);
-        do_tcp_packets          = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP packets", 1);
-        do_tcp_errors           = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP errors", 1);
-        do_tcp_handshake        = config_get_boolean("plugin:freebsd:sysctl", "ipv4 TCP handshake issues", 1);
-        do_ecn                  = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ECN packets", CONFIG_BOOLEAN_AUTO);
-        do_tcpext_syscookies    = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP SYN cookies", CONFIG_BOOLEAN_AUTO);
-        do_tcpext_ofo           = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP out-of-order queue", CONFIG_BOOLEAN_AUTO);
-        do_tcpext_connaborts    = config_get_boolean_ondemand("plugin:freebsd:sysctl", "TCP connection aborts", CONFIG_BOOLEAN_AUTO);
-        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);
-        do_ip_errors            = config_get_boolean("plugin:freebsd:sysctl", "ipv4 errors", 1);
-        do_ip6_packets          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 packets", CONFIG_BOOLEAN_AUTO);
-        do_ip6_fragsout         = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments sent", CONFIG_BOOLEAN_AUTO);
-        do_ip6_fragsin          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 fragments assembly", CONFIG_BOOLEAN_AUTO);
-        do_ip6_errors           = config_get_boolean_ondemand("plugin:freebsd:sysctl", "ipv6 errors", CONFIG_BOOLEAN_AUTO);
-        do_icmp6                = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_redir          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp redirects", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_errors         = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp errors", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_echos          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp echos", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_router         = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp router", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_neighbor       = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp neighbor", CONFIG_BOOLEAN_AUTO);
-        do_icmp6_types          = config_get_boolean_ondemand("plugin:freebsd:sysctl", "icmp types", CONFIG_BOOLEAN_AUTO);
-        do_space                = config_get_boolean("plugin:freebsd:sysctl", "space usage for all disks", 1);
-        do_inodes               = config_get_boolean("plugin:freebsd:sysctl", "inodes usage for all disks", 1);
-        do_uptime               = config_get_boolean("plugin:freebsd:sysctl", "system uptime", 1);
+int freebsd_plugin_init()
+{
+    system_pagesize = getpagesize();
+    if (system_pagesize <= 0) {
+        error("FREEBSD: can't get system page size");
+        return 1;
     }
 
-    RRDSET *st;
-    RRDDIM *rd;
-
-    int system_pagesize = getpagesize(); // wouldn't it be better to get value directly from hw.pagesize?
-    int i, n;
-    void *p;
-    int common_error = 0;
-    size_t size;
-    char title[4096 + 1];
-
-    // NEEDED BY: do_loadavg
-    static usec_t next_loadavg_dt = 0;
-    struct loadavg sysload;
-
-    // NEEDED BY: do_cpu, do_cpu_cores
-    long cp_time[CPUSTATES];
-
-    // NEEDED BY: du_cpu_cores, do_netisr, do_netisr_per_core
-    int ncpus;
-
-    // NEEDED BY: do_cpu_cores
-    static long *pcpu_cp_time = NULL;
-    char cpuid[MAX_INT_DIGITS + 1];
-
-    // NEEDED BY: do_all_processes, do_processes
-    struct vmtotal vmtotal_data;
-
-    // NEEDED BY: do_context, do_forks
-    u_int u_int_data;
-
-    // NEEDED BY: do_interrupts
-    size_t intrcnt_size;
-    unsigned long nintr = 0;
-    static unsigned long *intrcnt = NULL;
-    static char *intrnames = NULL;
-    unsigned long long totalintr = 0;
-
-    // NEEDED BY: do_disk_io
-    #define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
-    int numdevs;
-    static void *devstat_data = NULL;
-    struct devstat *dstat;
-    char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
-    struct cur_dstat {
-        collected_number duration_read_ms;
-        collected_number duration_write_ms;
-        collected_number busy_time_ms;
-    } cur_dstat;
-    struct prev_dstat {
-        collected_number bytes_read;
-        collected_number bytes_write;
-        collected_number operations_read;
-        collected_number operations_write;
-        collected_number duration_read_ms;
-        collected_number duration_write_ms;
-        collected_number busy_time_ms;
-    } prev_dstat;
-
-    // NEEDED BY: do_swap
-    size_t mibsize;
-    int mib[3]; // CTL_MAXNAME = 24 maximum mib components (sysctl.h)
-    struct xswdev xsw;
-    struct total_xsw {
-        collected_number bytes_used;
-        collected_number bytes_total;
-    } total_xsw = {0, 0};
-
-    // NEEDED BY: do_swapio, do_ram
-    struct vmmeter vmmeter_data;
-
-    // NEEDED BY: do_ram
-    int vfs_bufspace_count;
-
-    // NEEDED BY: do_ipc_semaphores
-    struct ipc_sem {
-        int semmni;
-        collected_number sets;
-        collected_number semaphores;
-    } ipc_sem = {0, 0, 0};
-    static struct semid_kernel *ipc_sem_data = NULL;
-
-    // NEEDED BY: do_ipc_shared_mem
-    struct ipc_shm {
-        u_long shmmni;
-        collected_number segs;
-        collected_number segsize;
-    } ipc_shm = {0, 0, 0};
-    static struct shmid_kernel *ipc_shm_data = NULL;
-
-    // NEEDED BY: do_ipc_msg_queues
-    struct ipc_msq {
-        int msgmni;
-        collected_number queues;
-        collected_number messages;
-        collected_number usedsize;
-        collected_number allocsize;
-    } ipc_msq = {0, 0, 0, 0, 0};
-    static struct msqid_kernel *ipc_msq_data = NULL;
+    if (unlikely(GETSYSCTL_BY_NAME("kern.smp.cpus", number_of_cpus))) {
+        error("FREEBSD: can't get number of cpus");
+        return 1;
+    }
 
-    // NEEDED BY: do_netisr, do_netisr_per_core
-    size_t netisr_workstream_size;
-    size_t netisr_work_size;
-    unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
-    static struct sysctl_netisr_workstream *netisr_workstream = NULL;
-    static struct sysctl_netisr_work *netisr_work = NULL;
-    static struct netisr_stats {
-        collected_number dispatched;
-        collected_number hybrid_dispatched;
-        collected_number qdrops;
-        collected_number queued;
-    } *netisr_stats = NULL;
-    char netstat_cpuid[21]; // no more than 4 digits expected
+    if (unlikely(!number_of_cpus)) {
+        error("FREEBSD: wrong number of cpus");
+        return 1;
+    }
 
-    // NEEDED BY: do_bandwidth
-    struct ifaddrs *ifa, *ifap;
-    struct iftot {
-        u_long  ift_ibytes;
-        u_long  ift_obytes;
-    } iftot = {0, 0};
+    return 0;
+}
 
-    // NEEDED BY: do_tcp...
-    struct tcpstat tcpstat;
-    uint64_t tcps_states[TCP_NSTATES];
+// --------------------------------------------------------------------------------------------------------------------
+// vm.loadavg
 
-    // NEEDED BY: do_udp...
-    struct udpstat udpstat;
+// FreeBSD calculates load averages once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
 
-    // NEEDED BY: do_icmp...
-    struct icmpstat icmpstat;
-    struct icmp_total {
-        u_long  msgs_in;
-        u_long  msgs_out;
-    } icmp_total = {0, 0};
+int do_vm_loadavg(int update_every, usec_t dt){
+    static usec_t next_loadavg_dt = 0;
 
-    // NEEDED BY: do_ip...
-    struct ipstat ipstat;
+    if (next_loadavg_dt <= dt) {
+        static int mib[2] = {0, 0};
+        struct loadavg sysload;
 
-    // NEEDED BY: do_ip6...
-    struct ip6stat ip6stat;
+        if (unlikely(GETSYSCTL_SIMPLE("vm.loadavg", mib, sysload))) {
+            error("DISABLED: system.load chart");
+            error("DISABLED: vm.loadavg module");
+            return 1;
+        } else {
 
-    // NEEDED BY: do_icmp6...
-    struct icmp6stat icmp6stat;
-    struct icmp6_total {
-        u_long  msgs_in;
-        u_long  msgs_out;
-    } icmp6_total = {0, 0};
+            // --------------------------------------------------------------------
 
-    // NEEDED BY: do_space, do_inodes
-    struct statfs *mntbuf;
-    int mntsize;
-    char mntonname[MNAMELEN + 1];
+            static RRDSET *st = NULL;
+            static RRDDIM *rd_load1 = NULL, *rd_load2 = NULL, *rd_load3 = NULL;
 
-    // NEEDED BY: do_uptime
-    struct timespec up_time;
+            if (unlikely(!st)) {
+                st = rrdset_create_localhost("system",
+                                             "load",
+                                             NULL,
+                                             "load",
+                                             NULL,
+                                             "System Load Average",
+                                             "load",
+                                             100,
+                                             (update_every < MIN_LOADAVG_UPDATE_EVERY) ?
+                                             MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE
+                );
+                rd_load1 = rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+                rd_load2 = rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+                rd_load3 = rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+            } else
+                rrdset_next(st);
+
+            rrddim_set_by_pointer(st, rd_load1, (collected_number) ((double) sysload.ldavg[0] / sysload.fscale * 1000));
+            rrddim_set_by_pointer(st, rd_load2, (collected_number) ((double) sysload.ldavg[1] / sysload.fscale * 1000));
+            rrddim_set_by_pointer(st, rd_load3, (collected_number) ((double) sysload.ldavg[2] / sysload.fscale * 1000));
+            rrdset_done(st);
 
-    // --------------------------------------------------------------------
+            next_loadavg_dt = st->update_every * USEC_PER_SEC;
+        }
+    }
+    else
+        next_loadavg_dt -= dt;
 
-    if (next_loadavg_dt <= dt) {
-        if (likely(do_loadavg)) {
-            if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
-                do_loadavg = 0;
-                error("DISABLED: system.load");
-            } else {
+    return 0;
+}
 
-                st = rrdset_find_bytype_localhost("system", "load");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
-                    rrddim_add(st, "load1", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
-                    rrddim_add(st, "load5", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
-                    rrddim_add(st, "load15", NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.vmtotal
 
-                rrddim_set(st, "load1", (collected_number) ((double)sysload.ldavg[0] / sysload.fscale * 1000));
-                rrddim_set(st, "load5", (collected_number) ((double)sysload.ldavg[1] / sysload.fscale * 1000));
-                rrddim_set(st, "load15", (collected_number) ((double)sysload.ldavg[2] / sysload.fscale * 1000));
-                rrdset_done(st);
+int do_vm_vmtotal(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_all_processes = -1, do_processes = -1, do_committed = -1;
 
-                next_loadavg_dt = st->update_every * USEC_PER_SEC;
-            }
-        }
+    if (unlikely(do_all_processes == -1)) {
+        do_all_processes    = config_get_boolean("plugin:freebsd:vm.vmtotal", "enable total processes", 1);
+        do_processes        = config_get_boolean("plugin:freebsd:vm.vmtotal", "processes running", 1);
+        do_committed        = config_get_boolean("plugin:freebsd:vm.vmtotal", "committed memory", 1);
     }
-    else next_loadavg_dt -= dt;
-
-    // --------------------------------------------------------------------
 
     if (likely(do_all_processes | do_processes | do_committed)) {
-        if (unlikely(GETSYSCTL("vm.vmtotal", vmtotal_data))) {
+        static int mib[2] = {0, 0};
+        struct vmtotal vmtotal_data;
+
+        if (unlikely(GETSYSCTL_SIMPLE("vm.vmtotal", mib, vmtotal_data))) {
             do_all_processes = 0;
-            error("DISABLED: system.active_processes");
+            error("DISABLED: system.active_processes chart");
             do_processes = 0;
-            error("DISABLED: system.processes");
+            error("DISABLED: system.processes chart");
             do_committed = 0;
-            error("DISABLED: mem.committed");
+            error("DISABLED: mem.committed chart");
+            error("DISABLED: vm.vmtotal module");
+            return 1;
         } else {
+
+            // --------------------------------------------------------------------
+
             if (likely(do_all_processes)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd = NULL;
 
-                st = rrdset_find_bytype_localhost("system", "active_processes");
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
-                    rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                    st = rrdset_create_localhost("system",
+                                                 "active_processes",
+                                                 NULL,
+                                                 "processes",
+                                                 NULL,
+                                                 "System Active Processes",
+                                                 "processes",
+                                                 750,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+                    rd = rrddim_add(st, "active", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "active", (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
+                rrddim_set_by_pointer(st, rd, (vmtotal_data.t_rq + vmtotal_data.t_dw + vmtotal_data.t_pw + vmtotal_data.t_sl + vmtotal_data.t_sw));
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_processes)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_running = NULL, *rd_blocked = NULL;
 
-                st = rrdset_find_bytype_localhost("system", "processes");
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                    rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
+                    st = rrdset_create_localhost("system",
+                                                 "processes",
+                                                 NULL,
+                                                 "processes",
+                                                 NULL,
+                                                 "System Processes",
+                                                 "processes",
+                                                 600,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_running = rrddim_add(st, "running", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                    rd_blocked = rrddim_add(st, "blocked", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "running", vmtotal_data.t_rq);
-                rrddim_set(st, "blocked", (vmtotal_data.t_dw + vmtotal_data.t_pw));
+                rrddim_set_by_pointer(st, rd_running, vmtotal_data.t_rq);
+                rrddim_set_by_pointer(st, rd_blocked, (vmtotal_data.t_dw + vmtotal_data.t_pw));
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_committed)) {
-                st = rrdset_find_localhost("mem.committed");
+                static RRDSET *st = NULL;
+                static RRDDIM *rd = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("mem", "committed", NULL, "system", NULL, "Committed (Allocated) Memory", "MB", 5000, update_every, RRDSET_TYPE_AREA);
+                    st = rrdset_create_localhost("mem",
+                                                 "committed",
+                                                 NULL,
+                                                 "system",
+                                                 NULL,
+                                                 "Committed (Allocated) Memory",
+                                                 "MB",
+                                                 5000,
+                                                 update_every,
+                                                 RRDSET_TYPE_AREA
+                    );
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+                    rd = rrddim_add(st, "Committed_AS", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "Committed_AS", vmtotal_data.t_rm);
+                rrddim_set_by_pointer(st, rd, vmtotal_data.t_rm);
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: vm.vmtotal module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_cpu)) {
-        if (unlikely(CPUSTATES != 5)) {
-            error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
-            do_cpu = 0;
-            error("DISABLED: system.cpu");
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_time
+
+int do_kern_cp_time(int update_every, usec_t dt) {
+    (void)dt;
+
+    if (unlikely(CPUSTATES != 5)) {
+        error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+        error("DISABLED: system.cpu chart");
+        error("DISABLED: kern.cp_time module");
+        return 1;
+    } else {
+        static int mib[2] = {0, 0};
+        long cp_time[CPUSTATES];
+
+        if (unlikely(GETSYSCTL_SIMPLE("kern.cp_time", mib, cp_time))) {
+            error("DISABLED: system.cpu chart");
+            error("DISABLED: kern.cp_time module");
+            return 1;
         } else {
-            if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
-                do_cpu = 0;
-                error("DISABLED: system.cpu");
-            } else {
 
-                st = rrdset_find_bytype_localhost("system", "cpu");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
-
-                    rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                    rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                    rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                    rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                    rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                    rrddim_hide(st, "idle");
-                }
-                else rrdset_next(st);
+            // --------------------------------------------------------------------
 
-                rrddim_set(st, "nice", cp_time[1]);
-                rrddim_set(st, "system", cp_time[2]);
-                rrddim_set(st, "user", cp_time[0]);
-                rrddim_set(st, "interrupt", cp_time[3]);
-                rrddim_set(st, "idle", cp_time[4]);
-                rrdset_done(st);
+            static RRDSET *st = NULL;
+            static RRDDIM *rd_nice = NULL, *rd_system = NULL, *rd_user = NULL, *rd_interrupt = NULL, *rd_idle = NULL;
+
+            if (unlikely(!st)) {
+                st = rrdset_create_localhost("system",
+                                             "cpu",
+                                             NULL,
+                                             "cpu",
+                                             "system.cpu",
+                                             "Total CPU utilization",
+                                             "percentage",
+                                             100, update_every,
+                                             RRDSET_TYPE_STACKED
+                );
+
+                rd_nice         = rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                rd_system       = rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                rd_user         = rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                rd_interrupt    = rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                rd_idle         = rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                rrddim_hide(st, "idle");
             }
+            else rrdset_next(st);
+
+            rrddim_set_by_pointer(st, rd_nice, cp_time[1]);
+            rrddim_set_by_pointer(st, rd_system, cp_time[2]);
+            rrddim_set_by_pointer(st, rd_user, cp_time[0]);
+            rrddim_set_by_pointer(st, rd_interrupt, cp_time[3]);
+            rrddim_set_by_pointer(st, rd_idle, cp_time[4]);
+            rrdset_done(st);
         }
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_cpu_cores)) {
-        if (unlikely(CPUSTATES != 5)) {
-            error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
-            do_cpu_cores = 0;
-            error("DISABLED: cpu.cpuXX");
+// --------------------------------------------------------------------------------------------------------------------
+// kern.cp_times
+
+int do_kern_cp_times(int update_every, usec_t dt) {
+    (void)dt;
+
+    if (unlikely(CPUSTATES != 5)) {
+        error("FREEBSD: There are %d CPU states (5 was expected)", CPUSTATES);
+        error("DISABLED: cpu.cpuXX charts");
+        error("DISABLED: kern.cp_times module");
+        return 1;
+    } else {
+        static int mib[2] = {0, 0};
+        long cp_time[CPUSTATES];
+        static long *pcpu_cp_time = NULL;
+
+        pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * number_of_cpus);
+        if (unlikely(GETSYSCTL_WSIZE("kern.cp_times", mib, pcpu_cp_time, sizeof(cp_time) * number_of_cpus))) {
+            error("DISABLED: cpu.cpuXX charts");
+            error("DISABLED: kern.cp_times module");
+            return 1;
         } else {
-            if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
-                do_cpu_cores = 0;
-                error("DISABLED: cpu.cpuXX");
-            } else {
-                pcpu_cp_time = reallocz(pcpu_cp_time, sizeof(cp_time) * ncpus);
-                if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
-                    do_cpu_cores = 0;
-                    error("DISABLED: cpu.cpuXX");
-                } else {
-                    for (i = 0; i < ncpus; i++) {
-                        snprintfz(cpuid, MAX_INT_DIGITS, "cpu%d", i);
-                        st = rrdset_find_bytype_localhost("cpu", cpuid);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization",
-                                               "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
-
-                            rrddim_add(st, "nice", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                            rrddim_add(st, "system", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                            rrddim_add(st, "user", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                            rrddim_add(st, "interrupt", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                            rrddim_add(st, "idle", NULL, 1, 1, RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
-                            rrddim_hide(st, "idle");
-                        } else
-                            rrdset_next(st);
-
-                        rrddim_set(st, "nice", pcpu_cp_time[i * 5 + 1]);
-                        rrddim_set(st, "system", pcpu_cp_time[i * 5 + 2]);
-                        rrddim_set(st, "user", pcpu_cp_time[i * 5 + 0]);
-                        rrddim_set(st, "interrupt", pcpu_cp_time[i * 5 + 3]);
-                        rrddim_set(st, "idle", pcpu_cp_time[i * 5 + 4]);
-                        rrdset_done(st);
-                }
-                }
+
+            // --------------------------------------------------------------------
+
+            int i;
+            static struct cpu_chart {
+                char cpuid[MAX_INT_DIGITS + 4];
+                RRDSET *st;
+                RRDDIM *rd_user;
+                RRDDIM *rd_nice;
+                RRDDIM *rd_system;
+                RRDDIM *rd_interrupt;
+                RRDDIM *rd_idle;
+            } *all_cpu_charts = NULL;
+            static int old_number_of_cpus = 0;
+
+            if(unlikely(number_of_cpus > old_number_of_cpus)) {
+                all_cpu_charts = reallocz(all_cpu_charts, sizeof(struct cpu_chart) * number_of_cpus);
+                memset(&all_cpu_charts[old_number_of_cpus], 0, sizeof(struct cpu_chart) * (number_of_cpus - old_number_of_cpus));
+                old_number_of_cpus = number_of_cpus;
+            }
+
+            for (i = 0; i < number_of_cpus; i++) {
+                if (unlikely(!all_cpu_charts[i].st)) {
+                    snprintfz(all_cpu_charts[i].cpuid, MAX_INT_DIGITS, "cpu%d", i);
+                    all_cpu_charts[i].st = rrdset_create_localhost("cpu",
+                                                                   all_cpu_charts[i].cpuid,
+                                                                   NULL,
+                                                                   "utilization",
+                                                                   "cpu.cpu",
+                                                                   "Core utilization",
+                                                                   "percentage",
+                                                                   1000,
+                                                                   update_every,
+                                                                   RRDSET_TYPE_STACKED
+                    );
+
+                    all_cpu_charts[i].rd_nice       = rrddim_add(all_cpu_charts[i].st, "nice", NULL, 1, 1,
+                                                                 RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                    all_cpu_charts[i].rd_system     = rrddim_add(all_cpu_charts[i].st, "system", NULL, 1, 1,
+                                                                 RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                    all_cpu_charts[i].rd_user       = rrddim_add(all_cpu_charts[i].st, "user", NULL, 1, 1,
+                                                                 RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                    all_cpu_charts[i].rd_interrupt  = rrddim_add(all_cpu_charts[i].st, "interrupt", NULL, 1, 1,
+                                                                 RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                    all_cpu_charts[i].rd_idle       = rrddim_add(all_cpu_charts[i].st, "idle", NULL, 1, 1,
+                                                                 RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL);
+                    rrddim_hide(all_cpu_charts[i].st, "idle");
+                } else rrdset_next(all_cpu_charts[i].st);
+
+                rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_nice, pcpu_cp_time[i * 5 + 1]);
+                rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_system, pcpu_cp_time[i * 5 + 2]);
+                rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_user, pcpu_cp_time[i * 5 + 0]);
+                rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_interrupt, pcpu_cp_time[i * 5 + 3]);
+                rrddim_set_by_pointer(all_cpu_charts[i].st, all_cpu_charts[i].rd_idle, pcpu_cp_time[i * 5 + 4]);
+                rrdset_done(all_cpu_charts[i].st);
             }
         }
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_interrupts)) {
-        if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
-            error("FREEBSD: sysctl(hw.intrcnt...) failed: %s", strerror(errno));
-            do_interrupts = 0;
-            error("DISABLED: system.intr");
+// --------------------------------------------------------------------------------------------------------------------
+// hw.intrcnt
+
+int do_hw_intcnt(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_hw_intrcnt[2] = {0, 0};
+    size_t intrcnt_size = sizeof(mib_hw_intrcnt);
+    unsigned long i;
+
+    if (unlikely(GETSYSCTL_SIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt_size))) {
+        error("DISABLED: system.intr chart");
+        error("DISABLED: system.interrupts chart");
+        error("DISABLED: hw.intrcnt module");
+        return 1;
+    } else {
+        unsigned long nintr = 0;
+        static unsigned long *intrcnt = NULL;
+        unsigned long long totalintr = 0;
+
+        nintr = intrcnt_size / sizeof(u_long);
+        intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
+        if (unlikely(GETSYSCTL_WSIZE("hw.intrcnt", mib_hw_intrcnt, intrcnt, nintr * sizeof(u_long)))) {
+            error("DISABLED: system.intr chart");
+            error("DISABLED: system.interrupts chart");
+            error("DISABLED: hw.intrcnt module");
+            return 1;
         } else {
-            nintr = intrcnt_size / sizeof(u_long);
-            intrcnt = reallocz(intrcnt, nintr * sizeof(u_long));
-            if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
-                do_interrupts = 0;
-                error("DISABLED: system.intr");
-            } else {
-                for (i = 0; i < nintr; i++)
-                    totalintr += intrcnt[i];
+            for (i = 0; i < nintr; i++)
+                totalintr += intrcnt[i];
 
-                st = rrdset_find_bytype_localhost("system", "intr");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "intr", NULL, "interrupts", NULL, "Total Hardware Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+            // --------------------------------------------------------------------
 
-                    rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
+            static RRDSET *st_intr = NULL;
+            static RRDDIM *rd_intr = NULL;
+
+            if (unlikely(!st_intr)) {
+                st_intr = rrdset_create_localhost("system",
+                                                  "intr",
+                                                  NULL,
+                                                  "interrupts",
+                                                  NULL,
+                                                  "Total Hardware Interrupts",
+                                                  "interrupts/s",
+                                                  900,
+                                                  update_every,
+                                                  RRDSET_TYPE_LINE
+                );
+                rrdset_flag_set(st_intr, RRDSET_FLAG_DETAIL);
+
+                rd_intr = rrddim_add(st_intr, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            } else
+                rrdset_next(st_intr);
+
+            rrddim_set_by_pointer(st_intr, rd_intr, totalintr);
+            rrdset_done(st_intr);
 
-                rrddim_set(st, "interrupts", totalintr);
-                rrdset_done(st);
+            // --------------------------------------------------------------------
 
-                // --------------------------------------------------------------------
+            size_t size;
+            static int mib_hw_intrnames[2] = {0, 0};
+            static char *intrnames = NULL;
+
+            size = nintr * (MAXCOMLEN + 1);
+            intrnames = reallocz(intrnames, size);
+            if (unlikely(GETSYSCTL_WSIZE("hw.intrnames", mib_hw_intrnames, intrnames, size))) {
+                error("DISABLED: system.intr chart");
+                error("DISABLED: system.interrupts chart");
+                error("DISABLED: hw.intrcnt module");
+                return 1;
+            } else {
 
-                size = nintr * (MAXCOMLEN +1);
-                intrnames = reallocz(intrnames, size);
-                if (unlikely(getsysctl("hw.intrnames", intrnames, size))) {
-                    do_interrupts = 0;
-                    error("DISABLED: system.intr");
-                } else {
-                    st = rrdset_find_bytype_localhost("system", "interrupts");
-                    if (unlikely(!st))
-                        st = rrdset_create_localhost("system", "interrupts", NULL, "interrupts", NULL, "System interrupts", "interrupts/s",
-                                           1000, update_every, RRDSET_TYPE_STACKED);
-                    else
-                        rrdset_next(st);
+                // --------------------------------------------------------------------
 
-                    for (i = 0; i < nintr; i++) {
-                        p = intrnames + i * (MAXCOMLEN + 1);
-                        if (unlikely((intrcnt[i] != 0) && (*(char*)p != 0))) {
-                            rd = rrddim_find(st, p);
-                            if (unlikely(!rd))
-                                rd = rrddim_add(st, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                            rrddim_set_by_pointer(st, rd, intrcnt[i]);
-                        }
+                static RRDSET *st_interrupts = NULL;
+                RRDDIM *rd_interrupts = NULL;
+                void *p;
+
+                if (unlikely(!st_interrupts))
+                    st_interrupts = rrdset_create_localhost("system",
+                                                            "interrupts",
+                                                            NULL,
+                                                            "interrupts",
+                                                            NULL,
+                                                            "System interrupts",
+                                                            "interrupts/s",
+                                                            1000,
+                                                            update_every,
+                                                            RRDSET_TYPE_STACKED
+                    );
+                else
+                    rrdset_next(st_interrupts);
+
+                for (i = 0; i < nintr; i++) {
+                    p = intrnames + i * (MAXCOMLEN + 1);
+                    if (unlikely((intrcnt[i] != 0) && (*(char *) p != 0))) {
+                        rd_interrupts = rrddim_find(st_interrupts, p);
+                        if (unlikely(!rd_interrupts))
+                            rd_interrupts = rrddim_add(st_interrupts, p, NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                        rrddim_set_by_pointer(st_interrupts, rd_interrupts, intrcnt[i]);
                     }
-                    rrdset_done(st);
                 }
+                rrdset_done(st_interrupts);
             }
         }
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_dev_intr)) {
-        if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", u_int_data))) {
-            do_dev_intr = 0;
-            error("DISABLED: system.dev_intr");
-        } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_intr
 
-            st = rrdset_find_bytype_localhost("system", "dev_intr");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "dev_intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 1000, update_every, RRDSET_TYPE_LINE);
+int do_vm_stats_sys_v_intr(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[4] = {0, 0, 0, 0};
+    u_int int_number;
 
-                rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_intr", mib, int_number))) {
+        error("DISABLED: system.dev_intr chart");
+        error("DISABLED: vm.stats.sys.v_intr module");
+        return 1;
+    } else {
 
-            rrddim_set(st, "interrupts", u_int_data);
-            rrdset_done(st);
-        }
-    }
+        // --------------------------------------------------------------------
 
-    // --------------------------------------------------------------------
+        static RRDSET *st = NULL;
+        static RRDDIM *rd = NULL;
 
-    if (likely(do_soft_intr)) {
-        if (unlikely(GETSYSCTL("vm.stats.sys.v_soft", u_int_data))) {
-            do_soft_intr = 0;
-            error("DISABLED: system.dev_intr");
-        } else {
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "dev_intr",
+                                         NULL,
+                                         "interrupts",
+                                         NULL,
+                                         "Device Interrupts",
+                                         "interrupts/s",
+                                         1000,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-            st = rrdset_find_bytype_localhost("system", "soft_intr");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "soft_intr", NULL, "interrupts", NULL, "Software Interrupts", "interrupts/s", 1100, update_every, RRDSET_TYPE_LINE);
+        rrddim_set_by_pointer(st, rd, int_number);
+        rrdset_done(st);
+    }
 
-                rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+    return 0;
+}
 
-            rrddim_set(st, "interrupts", u_int_data);
-            rrdset_done(st);
-        }
-    }
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_soft
 
-    // --------------------------------------------------------------------
+int do_vm_stats_sys_v_soft(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[4] = {0, 0, 0, 0};
+    u_int soft_intr_number;
 
-    if (likely(do_context)) {
-        if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", u_int_data))) {
-            do_context = 0;
-            error("DISABLED: system.ctxt");
-        } else {
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_soft", mib, soft_intr_number))) {
+        error("DISABLED: system.dev_intr chart");
+        error("DISABLED: vm.stats.sys.v_soft module");
+        return 1;
+    } else {
 
-            st = rrdset_find_bytype_localhost("system", "ctxt");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+        // --------------------------------------------------------------------
 
-                rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+        static RRDSET *st = NULL;
+        static RRDDIM *rd = NULL;
 
-            rrddim_set(st, "switches", u_int_data);
-            rrdset_done(st);
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "soft_intr",
+                                         NULL,
+                                         "interrupts",
+                                         NULL,
+                                         "Software Interrupts",
+                                         "interrupts/s",
+                                         1100,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rd = rrddim_add(st, "interrupts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else rrdset_next(st);
+
+        rrddim_set_by_pointer(st, rd, soft_intr_number);
+        rrdset_done(st);
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_forks)) {
-        if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", u_int_data))) {
-            do_forks = 0;
-            error("DISABLED: system.forks");
-        } else {
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.sys.v_swtch
 
-            st = rrdset_find_bytype_localhost("system", "forks");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
-                rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+int do_vm_stats_sys_v_swtch(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[4] = {0, 0, 0, 0};
+    u_int ctxt_number;
 
-                rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.sys.v_swtch", mib, ctxt_number))) {
+        error("DISABLED: system.ctxt chart");
+        error("DISABLED: vm.stats.sys.v_swtch module");
+        return 1;
+    } else {
 
-            rrddim_set(st, "started", u_int_data);
-            rrdset_done(st);
+        // --------------------------------------------------------------------
+
+        static RRDSET *st = NULL;
+        static RRDDIM *rd = NULL;
+
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "ctxt",
+                                         NULL,
+                                         "processes",
+                                         NULL,
+                                         "CPU Context Switches",
+                                         "context switches/s",
+                                         800,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rd = rrddim_add(st, "switches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else rrdset_next(st);
+
+        rrddim_set_by_pointer(st, rd, ctxt_number);
+        rrdset_done(st);
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_disk_io)) {
-        if (unlikely(GETSYSCTL("kern.devstat.numdevs", numdevs))) {
-            do_disk_io = 0;
-            error("DISABLED: disk.io");
-        } else {
-            devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
-            if (unlikely(getsysctl("kern.devstat.all", devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs))) {
-                do_disk_io = 0;
-                error("DISABLED: disk.io");
-            } else {
-                dstat = devstat_data + sizeof(long); // skip generation number
-                collected_number total_disk_kbytes_read = 0;
-                collected_number total_disk_kbytes_write = 0;
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_forks
 
-                for (i = 0; i < numdevs; i++) {
-                    if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
-                        sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+int do_vm_stats_sys_v_forks(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[4] = {0, 0, 0, 0};
+    u_int forks_number;
 
-                        // --------------------------------------------------------------------
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_forks", mib, forks_number))) {
+        error("DISABLED: system.forks chart");
+        error("DISABLED: vm.stats.sys.v_swtch module");
+        return 1;
+    } else {
 
-                        st = rrdset_find_bytype_localhost(RRD_TYPE_DISK, disk);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost(RRD_TYPE_DISK, disk, NULL, disk, "disk.io", "Disk I/O Bandwidth", "kilobytes/s", 2000, update_every, RRDSET_TYPE_AREA);
+        // --------------------------------------------------------------------
 
-                            rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_INCREMENTAL);
-                            rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_INCREMENTAL);
-                        }
-                        else rrdset_next(st);
+        static RRDSET *st = NULL;
+        static RRDDIM *rd = NULL;
 
-                        total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ]/KILO_FACTOR;
-                        total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE]/KILO_FACTOR;
-                        prev_dstat.bytes_read = rrddim_set(st, "reads", dstat[i].bytes[DEVSTAT_READ]);
-                        prev_dstat.bytes_write = rrddim_set(st, "writes", dstat[i].bytes[DEVSTAT_WRITE]);
-                        rrdset_done(st);
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "forks",
+                                         NULL,
+                                         "processes",
+                                         NULL,
+                                         "Started Processes",
+                                         "processes/s",
+                                         700,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+            rd = rrddim_add(st, "started", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-                        // --------------------------------------------------------------------
+        rrddim_set_by_pointer(st, rd, forks_number);
+        rrdset_done(st);
+    }
 
-                        st = rrdset_find_bytype_localhost("disk_ops", disk);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost("disk_ops", disk, NULL, disk, "disk.ops", "Disk Completed I/O Operations", "operations/s", 2001, update_every, RRDSET_TYPE_LINE);
-                            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+    return 0;
+}
 
-                            rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                            rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                        }
-                        else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.swap_info
+
+int do_vm_swap_info(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[3] = {0, 0, 0};
+
+    if (unlikely(getsysctl_mib("vm.swap_info", mib, 2))) {
+        error("DISABLED: system.swap chart");
+        error("DISABLED: vm.swap_info module");
+        return 1;
+    } else {
+        int i;
+        struct xswdev xsw;
+        struct total_xsw {
+            collected_number bytes_used;
+            collected_number bytes_total;
+        } total_xsw = {0, 0};
+
+        for (i = 0; ; i++) {
+            size_t size;
+
+            mib[2] = i;
+            size = sizeof(xsw);
+            if (unlikely(sysctl(mib, 3, &xsw, &size, NULL, 0) == -1 )) {
+                if (unlikely(errno != ENOENT)) {
+                    error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
+                    error("DISABLED: system.swap chart");
+                    error("DISABLED: vm.swap_info module");
+                    return 1;
+                } else {
+                    if (unlikely(size != sizeof(xsw))) {
+                        error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
+                        error("DISABLED: system.swap chart");
+                        error("DISABLED: vm.swap_info module");
+                        return 1;
+                    } else break;
+                }
+            }
+            total_xsw.bytes_used += xsw.xsw_used;
+            total_xsw.bytes_total += xsw.xsw_nblks;
+        }
 
-                        prev_dstat.operations_read = rrddim_set(st, "reads", dstat[i].operations[DEVSTAT_READ]);
-                        prev_dstat.operations_write = rrddim_set(st, "writes", dstat[i].operations[DEVSTAT_WRITE]);
-                        rrdset_done(st);
+        // --------------------------------------------------------------------
 
-                        // --------------------------------------------------------------------
+        static RRDSET *st = NULL;
+        static RRDDIM *rd_free = NULL, *rd_used = NULL;
 
-                        st = rrdset_find_bytype_localhost("disk_qops", disk);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost("disk_qops", disk, NULL, disk, "disk.qops", "Disk Current I/O Operations", "operations", 2002, update_every, RRDSET_TYPE_LINE);
-                            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "swap",
+                                         NULL,
+                                         "swap",
+                                         NULL,
+                                         "System Swap",
+                                         "MB",
+                                         201,
+                                         update_every,
+                                         RRDSET_TYPE_STACKED
+            );
+
+            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+            rd_free = rrddim_add(st, "free",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            rd_used = rrddim_add(st, "used",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+        }
+        else rrdset_next(st);
 
-                            rrddim_add(st, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                        }
-                        else rrdset_next(st);
+        rrddim_set_by_pointer(st, rd_free, total_xsw.bytes_total - total_xsw.bytes_used);
+        rrddim_set_by_pointer(st, rd_used, total_xsw.bytes_used);
+        rrdset_done(st);
+    }
 
-                        rrddim_set(st, "operations", dstat[i].start_count - dstat[i].end_count);
-                        rrdset_done(st);
+    return 0;
+}
 
-                        // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// system.ram
 
-                        st = rrdset_find_bytype_localhost("disk_util", disk);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost("disk_util", disk, NULL, disk, "disk.util", "Disk Utilization Time", "% of time working", 2004, update_every, RRDSET_TYPE_AREA);
-                            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+int do_system_ram(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_active_count[4] = {0, 0, 0, 0}, mib_inactive_count[4] = {0, 0, 0, 0}, mib_wire_count[4] = {0, 0, 0, 0},
+               mib_cache_count[4] = {0, 0, 0, 0}, mib_vfs_bufspace[2] = {0, 0}, mib_free_count[4] = {0, 0, 0, 0};
+    struct vmmeter vmmeter_data;
+    int vfs_bufspace_count;
 
-                            rrddim_add(st, "utilization", NULL, 1, 10, RRD_ALGORITHM_INCREMENTAL);
-                        }
-                        else rrdset_next(st);
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_active_count",   mib_active_count,   vmmeter_data.v_active_count) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_inactive_count", mib_inactive_count, vmmeter_data.v_inactive_count) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_wire_count",     mib_wire_count,     vmmeter_data.v_wire_count) ||
+#if __FreeBSD_version < 1200016
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_cache_count",    mib_cache_count,    vmmeter_data.v_cache_count) ||
+#endif
+                 GETSYSCTL_SIMPLE("vfs.bufspace",                 mib_vfs_bufspace,     vfs_bufspace_count) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_free_count",     mib_free_count,     vmmeter_data.v_free_count))) {
+        error("DISABLED: system.ram chart");
+        error("DISABLED: System.ram module");
+        return 1;
+    } else {
 
-                        cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
-                        prev_dstat.busy_time_ms = rrddim_set(st, "utilization", cur_dstat.busy_time_ms);
-                        rrdset_done(st);
+        // --------------------------------------------------------------------
 
-                        // --------------------------------------------------------------------
+        static RRDSET *st = NULL;
+        static RRDDIM *rd_free = NULL, *rd_active = NULL, *rd_inactive = NULL,
+                      *rd_wired = NULL, *rd_cache = NULL, *rd_buffers = NULL;
 
-                        st = rrdset_find_bytype_localhost("disk_iotime", disk);
-                        if (unlikely(!st)) {
-                            st = rrdset_create_localhost("disk_iotime", disk, NULL, disk, "disk.iotime", "Disk Total I/O Time", "milliseconds/s", 2022, update_every, RRDSET_TYPE_LINE);
-                            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+        st = rrdset_find_localhost("system.ram");
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "ram",
+                                         NULL,
+                                         "ram",
+                                         NULL,
+                                         "System RAM",
+                                         "MB",
+                                         200,
+                                         update_every,
+                                         RRDSET_TYPE_STACKED
+            );
+
+            rd_free     = rrddim_add(st, "free",     NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            rd_active   = rrddim_add(st, "active",   NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            rd_inactive = rrddim_add(st, "inactive", NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            rd_wired    = rrddim_add(st, "wired",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#if __FreeBSD_version < 1200016
+            rd_cache    = rrddim_add(st, "cache",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+#endif
+            rd_buffers  = rrddim_add(st, "buffers",  NULL, 1, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+        }
+        else rrdset_next(st);
 
-                            rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                            rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                        }
-                        else rrdset_next(st);
+        rrddim_set_by_pointer(st, rd_free,     vmmeter_data.v_free_count);
+        rrddim_set_by_pointer(st, rd_active,   vmmeter_data.v_active_count);
+        rrddim_set_by_pointer(st, rd_inactive, vmmeter_data.v_inactive_count);
+        rrddim_set_by_pointer(st, rd_wired,    vmmeter_data.v_wire_count);
+#if __FreeBSD_version < 1200016
+        rrddim_set_by_pointer(st, rd_cache,    vmmeter_data.v_cache_count);
+#endif
+        rrddim_set_by_pointer(st, rd_buffers,  vfs_bufspace_count);
+        rrdset_done(st);
+    }
 
-                        cur_dstat.duration_read_ms = dstat[i].duration[DEVSTAT_READ].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
-                        cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000 + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
-                        prev_dstat.duration_read_ms = rrddim_set(st, "reads", cur_dstat.duration_read_ms);
-                        prev_dstat.duration_write_ms = rrddim_set(st, "writes", cur_dstat.duration_write_ms);
-                        rrdset_done(st);
+    return 0;
+}
 
-                        // --------------------------------------------------------------------
-                        // calculate differential charts
-                        // only if this is not the first time we run
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_swappgs
 
-                        if (likely(dt)) {
+int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_swappgsin[4] = {0, 0, 0, 0}, mib_swappgsout[4] = {0, 0, 0, 0};
+    struct vmmeter vmmeter_data;
 
-                            // --------------------------------------------------------------------
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsin", mib_swappgsin, vmmeter_data.v_swappgsin) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_swappgsout", mib_swappgsout, vmmeter_data.v_swappgsout))) {
+        error("DISABLED: system.swapio chart");
+        error("DISABLED: vm.stats.vm.v_swappgs module");
+        return 1;
+    } else {
 
-                            st = rrdset_find_bytype_localhost("disk_await", disk);
-                            if (unlikely(!st)) {
-                                st = rrdset_create_localhost("disk_await", disk, NULL, disk, "disk.await", "Average Completed I/O Operation Time", "ms per operation", 2005, update_every, RRDSET_TYPE_LINE);
-                                rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+        // --------------------------------------------------------------------
 
-                                rrddim_add(st, "reads", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                                rrddim_add(st, "writes", NULL, -1, 1, RRD_ALGORITHM_ABSOLUTE);
-                            }
-                            else rrdset_next(st);
+        static RRDSET *st = NULL;
+        static RRDDIM *rd_in = NULL, *rd_out = NULL;
 
-                            rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
-                                (cur_dstat.duration_read_ms - prev_dstat.duration_read_ms) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
-                            rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
-                                (cur_dstat.duration_write_ms - prev_dstat.duration_write_ms) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
-                            rrdset_done(st);
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("system",
+                                         "swapio",
+                                         NULL,
+                                         "swap",
+                                         NULL,
+                                         "Swap I/O",
+                                         "kilobytes/s",
+                                         250,
+                                         update_every,
+                                         RRDSET_TYPE_AREA
+            );
+
+            rd_in = rrddim_add(st, "in",  NULL, system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+            rd_out = rrddim_add(st, "out", NULL, -system_pagesize, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+        }
+        else rrdset_next(st);
 
-                            // --------------------------------------------------------------------
+        rrddim_set_by_pointer(st, rd_in, vmmeter_data.v_swappgsin);
+        rrddim_set_by_pointer(st, rd_out, vmmeter_data.v_swappgsout);
+        rrdset_done(st);
+    }
 
-                            st = rrdset_find_bytype_localhost("disk_avgsz", disk);
-                            if (unlikely(!st)) {
-                                st = rrdset_create_localhost("disk_avgsz", disk, NULL, disk, "disk.avgsz", "Average Completed I/O Operation Bandwidth", "kilobytes per operation", 2006, update_every, RRDSET_TYPE_AREA);
-                                rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+    return 0;
+}
 
-                                rrddim_add(st, "reads", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
-                                rrddim_add(st, "writes", NULL, -1, 1024, RRD_ALGORITHM_ABSOLUTE);
-                            }
-                            else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// vm.stats.vm.v_pgfaults
 
-                            rrddim_set(st, "reads", (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) ?
-                                (dstat[i].bytes[DEVSTAT_READ] - prev_dstat.bytes_read) / (dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) : 0);
-                            rrddim_set(st, "writes", (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) ?
-                                (dstat[i].bytes[DEVSTAT_WRITE] - prev_dstat.bytes_write) / (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write) : 0);
-                            rrdset_done(st);
+int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_vm_faults[4] = {0, 0, 0, 0}, mib_io_faults[4] = {0, 0, 0, 0}, mib_cow_faults[4] = {0, 0, 0, 0},
+               mib_cow_optim[4] = {0, 0, 0, 0}, mib_intrans[4] = {0, 0, 0, 0};
+    struct vmmeter vmmeter_data;
 
-                            // --------------------------------------------------------------------
+    if (unlikely(GETSYSCTL_SIMPLE("vm.stats.vm.v_vm_faults",  mib_vm_faults,  vmmeter_data.v_vm_faults) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_io_faults",  mib_io_faults,  vmmeter_data.v_io_faults) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_faults", mib_cow_faults, vmmeter_data.v_cow_faults) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_cow_optim",  mib_cow_optim,  vmmeter_data.v_cow_optim) ||
+                 GETSYSCTL_SIMPLE("vm.stats.vm.v_intrans",    mib_intrans,    vmmeter_data.v_intrans))) {
+        error("DISABLED: mem.pgfaults chart");
+        error("DISABLED: vm.stats.vm.v_pgfaults module");
+        return 1;
+    } else {
 
-                            st = rrdset_find_bytype_localhost("disk_svctm", disk);
-                            if (unlikely(!st)) {
-                                st = rrdset_create_localhost("disk_svctm", disk, NULL, disk, "disk.svctm", "Average Service Time", "ms per operation", 2007, update_every, RRDSET_TYPE_LINE);
-                                rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+        // --------------------------------------------------------------------
 
-                                rrddim_add(st, "svctm", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                            }
-                            else rrdset_next(st);
-
-                            rrddim_set(st, "svctm", ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) ?
-                                (cur_dstat.busy_time_ms - prev_dstat.busy_time_ms) / ((dstat[i].operations[DEVSTAT_READ] - prev_dstat.operations_read) + (dstat[i].operations[DEVSTAT_WRITE] - prev_dstat.operations_write)) : 0);
-                            rrdset_done(st);
-                        }
-                    }
-                }
-
-                // --------------------------------------------------------------------
-
-                st = rrdset_find_bytype_localhost("system", "io");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "io", NULL, "disk", NULL, "Disk I/O", "kilobytes/s", 150, update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "in",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
+        static RRDSET *st = NULL;
+        static RRDDIM *rd_memory = NULL, *rd_io_requiring = NULL, *rd_cow = NULL,
+                      *rd_cow_optimized = NULL, *rd_in_transit = NULL;
 
-                rrddim_set(st, "in", total_disk_kbytes_read);
-                rrddim_set(st, "out", total_disk_kbytes_write);
-                rrdset_done(st);
-            }
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("mem",
+                                         "pgfaults",
+                                         NULL,
+                                         "system",
+                                         NULL,
+                                         "Memory Page Faults",
+                                         "page faults/s",
+                                         500,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+            rd_memory        = rrddim_add(st, "memory",        NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_io_requiring  = rrddim_add(st, "io_requiring",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_cow           = rrddim_add(st, "cow",           NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_cow_optimized = rrddim_add(st, "cow_optimized", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_in_transit    = rrddim_add(st, "in_transit",    NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else rrdset_next(st);
+
+        rrddim_set_by_pointer(st, rd_memory,        vmmeter_data.v_vm_faults);
+        rrddim_set_by_pointer(st, rd_io_requiring,  vmmeter_data.v_io_faults);
+        rrddim_set_by_pointer(st, rd_cow,           vmmeter_data.v_cow_faults);
+        rrddim_set_by_pointer(st, rd_cow_optimized, vmmeter_data.v_cow_optim);
+        rrddim_set_by_pointer(st, rd_in_transit,    vmmeter_data.v_intrans);
+        rrdset_done(st);
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.sem
+
+int do_kern_ipc_sem(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_semmni[3] = {0, 0, 0}, mib_sema[3] = {0, 0, 0};
+    struct ipc_sem {
+        int semmni;
+        collected_number sets;
+        collected_number semaphores;
+    } ipc_sem = {0, 0, 0};
 
-    if (likely(do_swap)) {
-        mibsize = sizeof mib / sizeof mib[0];
-        if (unlikely(sysctlnametomib("vm.swap_info", mib, &mibsize) == -1)) {
-            error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
-            do_swap = 0;
-            error("DISABLED: system.swap");
+    if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.semmni", mib_semmni, ipc_sem.semmni))) {
+        error("DISABLED: system.ipc_semaphores chart");
+        error("DISABLED: system.ipc_semaphore_arrays chart");
+        error("DISABLED: kern.ipc.sem module");
+        return 1;
+    } else {
+        static struct semid_kernel *ipc_sem_data = NULL;
+
+        ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
+        if (unlikely(GETSYSCTL_WSIZE("kern.ipc.sema", mib_sema, ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
+            error("DISABLED: system.ipc_semaphores chart");
+            error("DISABLED: system.ipc_semaphore_arrays chart");
+            error("DISABLED: kern.ipc.sem module");
+            return 1;
         } else {
-            for (i = 0; ; i++) {
-                mib[mibsize] = i;
-                size = sizeof(xsw);
-                if (unlikely(sysctl(mib, mibsize + 1, &xsw, &size, NULL, 0) == -1 )) {
-                    if (unlikely(errno != ENOENT)) {
-                        error("FREEBSD: sysctl(%s...) failed: %s", "vm.swap_info", strerror(errno));
-                        do_swap = 0;
-                        error("DISABLED: system.swap");
-                    } else {
-                        if (unlikely(size != sizeof(xsw))) {
-                            error("FREEBSD: sysctl(%s...) expected %lu, got %lu", "vm.swap_info", (unsigned long)sizeof(xsw), (unsigned long)size);
-                            do_swap = 0;
-                            error("DISABLED: system.swap");
-                        } else break;
-                    }
+            int i;
+
+            for (i = 0; i < ipc_sem.semmni; i++) {
+                if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
+                    ipc_sem.sets += 1;
+                    ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
                 }
-                total_xsw.bytes_used += xsw.xsw_used;
-                total_xsw.bytes_total += xsw.xsw_nblks;
             }
 
-            if (likely(do_swap)) {
-                st = rrdset_find_localhost("system.swap");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "swap", NULL, "swap", NULL, "System Swap", "MB", 201, update_every, RRDSET_TYPE_STACKED);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
-                    rrddim_add(st, "free",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                    rrddim_add(st, "used",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+            // --------------------------------------------------------------------
 
-                rrddim_set(st, "used", total_xsw.bytes_used);
-                rrddim_set(st, "free", total_xsw.bytes_total - total_xsw.bytes_used);
-                rrdset_done(st);
+            static RRDSET *st_semaphores = NULL, *st_semaphore_arrays = NULL;
+            static RRDDIM *rd_semaphores = NULL, *rd_semaphore_arrays = NULL;
+
+            if (unlikely(!st_semaphores)) {
+                st_semaphores = rrdset_create_localhost("system",
+                                                        "ipc_semaphores",
+                                                        NULL,
+                                                        "ipc semaphores",
+                                                        NULL,
+                                                        "IPC Semaphores",
+                                                        "semaphores",
+                                                        1000,
+                                                        update_every,
+                                                        RRDSET_TYPE_AREA
+                );
+
+                rd_semaphores = rrddim_add(st_semaphores, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
             }
-        }
-    }
+            else rrdset_next(st_semaphores);
 
-    // --------------------------------------------------------------------
+            rrddim_set_by_pointer(st_semaphores, rd_semaphores, ipc_sem.semaphores);
+            rrdset_done(st_semaphores);
 
-    if (likely(do_ram)) {
-        if (unlikely(GETSYSCTL("vm.stats.vm.v_active_count",    vmmeter_data.v_active_count) ||
-                     GETSYSCTL("vm.stats.vm.v_inactive_count",  vmmeter_data.v_inactive_count) ||
-                     GETSYSCTL("vm.stats.vm.v_wire_count",      vmmeter_data.v_wire_count) ||
-#if __FreeBSD_version < 1200016
-                     GETSYSCTL("vm.stats.vm.v_cache_count",     vmmeter_data.v_cache_count) ||
-#endif
-                     GETSYSCTL("vfs.bufspace",                  vfs_bufspace_count) ||
-                     GETSYSCTL("vm.stats.vm.v_free_count",      vmmeter_data.v_free_count))) {
-            do_ram = 0;
-            error("DISABLED: system.ram");
-        } else {
-            st = rrdset_find_localhost("system.ram");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "ram", NULL, "ram", NULL, "System RAM", "MB", 200, update_every, RRDSET_TYPE_STACKED);
+            // --------------------------------------------------------------------
 
-                rrddim_add(st, "active",    NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                rrddim_add(st, "inactive",  NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                rrddim_add(st, "wired",     NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-#if __FreeBSD_version < 1200016
-                rrddim_add(st, "cache",     NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-#endif
-                rrddim_add(st, "buffers",   NULL, 1, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                rrddim_add(st, "free",      NULL, system_pagesize, MEGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            if (unlikely(!st_semaphore_arrays)) {
+                st_semaphore_arrays = rrdset_create_localhost("system",
+                                                              "ipc_semaphore_arrays",
+                                                              NULL,
+                                                              "ipc semaphores",
+                                                              NULL,
+                                                              "IPC Semaphore Arrays",
+                                                              "arrays",
+                                                              1000,
+                                                              update_every,
+                                                              RRDSET_TYPE_AREA
+                );
+
+                rd_semaphore_arrays = rrddim_add(st_semaphore_arrays, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
             }
-            else rrdset_next(st);
+            else rrdset_next(st_semaphore_arrays);
 
-            rrddim_set(st, "active",    vmmeter_data.v_active_count);
-            rrddim_set(st, "inactive",  vmmeter_data.v_inactive_count);
-            rrddim_set(st, "wired",     vmmeter_data.v_wire_count);
-#if __FreeBSD_version < 1200016
-            rrddim_set(st, "cache",     vmmeter_data.v_cache_count);
-#endif
-            rrddim_set(st, "buffers",   vfs_bufspace_count);
-            rrddim_set(st, "free",      vmmeter_data.v_free_count);
-            rrdset_done(st);
+            rrddim_set_by_pointer(st_semaphore_arrays, rd_semaphore_arrays, ipc_sem.sets);
+            rrdset_done(st_semaphore_arrays);
         }
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.shm
+
+int do_kern_ipc_shm(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_shmmni[3] = {0, 0, 0}, mib_shmsegs[3] = {0, 0, 0};
+    struct ipc_shm {
+        u_long shmmni;
+        collected_number segs;
+        collected_number segsize;
+    } ipc_shm = {0, 0, 0};
 
-    if (likely(do_swapio)) {
-        if (unlikely(GETSYSCTL("vm.stats.vm.v_swappgsin", vmmeter_data.v_swappgsin) || GETSYSCTL("vm.stats.vm.v_swappgsout", vmmeter_data.v_swappgsout))) {
-            do_swapio = 0;
-            error("DISABLED: system.swapio");
+    if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.shmmni", mib_shmmni, ipc_shm.shmmni))) {
+        error("DISABLED: system.ipc_shared_mem_segs chart");
+        error("DISABLED: system.ipc_shared_mem_size chart");
+        error("DISABLED: kern.ipc.shmmodule");
+        return 1;
+    } else {
+        static struct shmid_kernel *ipc_shm_data = NULL;
+
+        ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
+        if (unlikely(
+                GETSYSCTL_WSIZE("kern.ipc.shmsegs", mib_shmsegs, ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
+            error("DISABLED: system.ipc_shared_mem_segs chart");
+            error("DISABLED: system.ipc_shared_mem_size chart");
+            error("DISABLED: kern.ipc.shmmodule");
+            return 1;
         } else {
-            st = rrdset_find_localhost("system.swapio");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "swapio", NULL, "swap", NULL, "Swap I/O", "kilobytes/s", 250, update_every, RRDSET_TYPE_AREA);
+            unsigned long i;
 
-                rrddim_add(st, "in",  NULL, system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "out", NULL, -system_pagesize, 1024, RRD_ALGORITHM_INCREMENTAL);
+            for (i = 0; i < ipc_shm.shmmni; i++) {
+                if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
+                    ipc_shm.segs += 1;
+                    ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
+                }
             }
-            else rrdset_next(st);
-
-            rrddim_set(st, "in", vmmeter_data.v_swappgsin);
-            rrddim_set(st, "out", vmmeter_data.v_swappgsout);
-            rrdset_done(st);
-        }
-    }
 
-    // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
 
-    if (likely(do_pgfaults)) {
-        if (unlikely(GETSYSCTL("vm.stats.vm.v_vm_faults",   vmmeter_data.v_vm_faults) ||
-                     GETSYSCTL("vm.stats.vm.v_io_faults",   vmmeter_data.v_io_faults) ||
-                     GETSYSCTL("vm.stats.vm.v_cow_faults",  vmmeter_data.v_cow_faults) ||
-                     GETSYSCTL("vm.stats.vm.v_cow_optim",   vmmeter_data.v_cow_optim) ||
-                     GETSYSCTL("vm.stats.vm.v_intrans",     vmmeter_data.v_intrans))) {
-            do_pgfaults = 0;
-            error("DISABLED: mem.pgfaults");
-        } else {
-            st = rrdset_find_localhost("mem.pgfaults");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("mem", "pgfaults", NULL, "system", NULL, "Memory Page Faults", "page faults/s", 500, update_every, RRDSET_TYPE_LINE);
-                rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
-                rrddim_add(st, "memory", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "io_requiring", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "cow", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "cow_optimized", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "in_transit", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            static RRDSET *st_segs = NULL, *st_size = NULL;
+            static RRDDIM *rd_segments = NULL, *rd_allocated = NULL;
+
+            if (unlikely(!st_segs)) {
+                st_segs = rrdset_create_localhost("system",
+                                             "ipc_shared_mem_segs",
+                                             NULL,
+                                             "ipc shared memory",
+                                             NULL,
+                                             "IPC Shared Memory Segments",
+                                             "segments",
+                                             1000,
+                                             update_every,
+                                             RRDSET_TYPE_AREA
+                );
+
+                rd_segments = rrddim_add(st_segs, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
             }
-            else rrdset_next(st);
+            else rrdset_next(st_segs);
 
-            rrddim_set(st, "memory", vmmeter_data.v_vm_faults);
-            rrddim_set(st, "io_requiring", vmmeter_data.v_io_faults);
-            rrddim_set(st, "cow", vmmeter_data.v_cow_faults);
-            rrddim_set(st, "cow_optimized", vmmeter_data.v_cow_optim);
-            rrddim_set(st, "in_transit", vmmeter_data.v_intrans);
-            rrdset_done(st);
-        }
-    }
+            rrddim_set_by_pointer(st_segs, rd_segments, ipc_shm.segs);
+            rrdset_done(st_segs);
 
-    // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
 
-    if (likely(do_ipc_semaphores)) {
-        if (unlikely(GETSYSCTL("kern.ipc.semmni", ipc_sem.semmni))) {
-            do_ipc_semaphores = 0;
-            error("DISABLED: system.ipc_semaphores");
-            error("DISABLED: system.ipc_semaphore_arrays");
-        } else {
-            ipc_sem_data = reallocz(ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni);
-            if (unlikely(getsysctl("kern.ipc.sema", ipc_sem_data, sizeof(struct semid_kernel) * ipc_sem.semmni))) {
-                do_ipc_semaphores = 0;
-                error("DISABLED: system.ipc_semaphores");
-                error("DISABLED: system.ipc_semaphore_arrays");
-            } else {
-                for (i = 0; i < ipc_sem.semmni; i++) {
-                    if (unlikely(ipc_sem_data[i].u.sem_perm.mode & SEM_ALLOC)) {
-                        ipc_sem.sets += 1;
-                        ipc_sem.semaphores += ipc_sem_data[i].u.sem_nsems;
-                    }
-                }
+            if (unlikely(!st_size)) {
+                st_size = rrdset_create_localhost("system",
+                                             "ipc_shared_mem_size",
+                                             NULL,
+                                             "ipc shared memory",
+                                             NULL,
+                                             "IPC Shared Memory Segments Size",
+                                             "kilobytes",
+                                             1000,
+                                             update_every,
+                                             RRDSET_TYPE_AREA
+                );
+
+                rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, KILO_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+            }
+            else rrdset_next(st_size);
 
-                // --------------------------------------------------------------------
+            rrddim_set_by_pointer(st_size, rd_allocated, ipc_shm.segsize);
+            rrdset_done(st_size);
+        }
+    }
 
-                st = rrdset_find_localhost("system.ipc_semaphores");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_semaphores", NULL, "ipc semaphores", NULL, "IPC Semaphores", "semaphores", 1000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "semaphores", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+    return 0;
+}
 
-                rrddim_set(st, "semaphores", ipc_sem.semaphores);
-                rrdset_done(st);
+// --------------------------------------------------------------------------------------------------------------------
+// kern.ipc.msq
 
-                // --------------------------------------------------------------------
+int do_kern_ipc_msq(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib_msgmni[3] = {0, 0, 0}, mib_msqids[3] = {0, 0, 0};
+    struct ipc_msq {
+        int msgmni;
+        collected_number queues;
+        collected_number messages;
+        collected_number usedsize;
+        collected_number allocsize;
+    } ipc_msq = {0, 0, 0, 0, 0};
 
-                st = rrdset_find_localhost("system.ipc_semaphore_arrays");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_semaphore_arrays", NULL, "ipc semaphores", NULL, "IPC Semaphore Arrays", "arrays", 1000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "arrays", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+    if (unlikely(GETSYSCTL_SIMPLE("kern.ipc.msgmni", mib_msgmni, ipc_msq.msgmni))) {
+        error("DISABLED: system.ipc_msq_queues chart");
+        error("DISABLED: system.ipc_msq_messages chart");
+        error("DISABLED: system.ipc_msq_size chart");
+        error("DISABLED: kern.ipc.msg module");
+        return 1;
+    } else {
+        static struct msqid_kernel *ipc_msq_data = NULL;
+
+        ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
+        if (unlikely(
+                GETSYSCTL_WSIZE("kern.ipc.msqids", mib_msqids, ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
+            error("DISABLED: system.ipc_msq_queues chart");
+            error("DISABLED: system.ipc_msq_messages chart");
+            error("DISABLED: system.ipc_msq_size chart");
+            error("DISABLED: kern.ipc.msg module");
+            return 1;
+        } else {
+            int i;
+
+            for (i = 0; i < ipc_msq.msgmni; i++) {
+                if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
+                    ipc_msq.queues += 1;
+                    ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
+                    ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
+                    ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
                 }
-                else rrdset_next(st);
-
-                rrddim_set(st, "arrays", ipc_sem.sets);
-                rrdset_done(st);
             }
-        }
-    }
 
-    // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
 
-    if (likely(do_ipc_shared_mem)) {
-        if (unlikely(GETSYSCTL("kern.ipc.shmmni", ipc_shm.shmmni))) {
-            do_ipc_shared_mem = 0;
-            error("DISABLED: system.ipc_shared_mem_segs");
-            error("DISABLED: system.ipc_shared_mem_size");
-        } else {
-            ipc_shm_data = reallocz(ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni);
-            if (unlikely(getsysctl("kern.ipc.shmsegs", ipc_shm_data, sizeof(struct shmid_kernel) * ipc_shm.shmmni))) {
-                do_ipc_shared_mem = 0;
-                error("DISABLED: system.ipc_shared_mem_segs");
-                error("DISABLED: system.ipc_shared_mem_size");
-            } else {
-                for (i = 0; i < ipc_shm.shmmni; i++) {
-                    if (unlikely(ipc_shm_data[i].u.shm_perm.mode & 0x0800)) {
-                        ipc_shm.segs += 1;
-                        ipc_shm.segsize += ipc_shm_data[i].u.shm_segsz;
-                    }
-                }
+            static RRDSET *st_queues = NULL, *st_messages = NULL, *st_size = NULL;
+            static RRDDIM *rd_queues = NULL, *rd_messages = NULL, *rd_allocated = NULL, *rd_used = NULL;
+
+            if (unlikely(!st_queues)) {
+                st_queues = rrdset_create_localhost("system",
+                                                    "ipc_msq_queues",
+                                                    NULL,
+                                                    "ipc message queues",
+                                                    NULL,
+                                                    "Number of IPC Message Queues",
+                                                    "queues",
+                                                    990,
+                                                    update_every,
+                                                    RRDSET_TYPE_AREA
+                );
+
+                rd_queues = rrddim_add(st_queues, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+            }
+            else rrdset_next(st_queues);
 
-                // --------------------------------------------------------------------
+            rrddim_set_by_pointer(st_queues, rd_queues, ipc_msq.queues);
+            rrdset_done(st_queues);
 
-                st = rrdset_find_localhost("system.ipc_shared_mem_segs");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_shared_mem_segs", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments", "segments", 1000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "segments", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+            // --------------------------------------------------------------------
 
-                rrddim_set(st, "segments", ipc_shm.segs);
-                rrdset_done(st);
+            if (unlikely(!st_messages)) {
+                st_messages = rrdset_create_localhost("system",
+                                                      "ipc_msq_messages",
+                                                      NULL,
+                                                      "ipc message queues",
+                                                      NULL,
+                                                      "Number of Messages in IPC Message Queues",
+                                                      "messages",
+                                                      1000,
+                                                      update_every,
+                                                      RRDSET_TYPE_AREA
+                );
+
+                rd_messages = rrddim_add(st_messages, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+            }
+            else rrdset_next(st_messages);
 
-                // --------------------------------------------------------------------
+            rrddim_set_by_pointer(st_messages, rd_messages, ipc_msq.messages);
+            rrdset_done(st_messages);
 
-                st = rrdset_find_localhost("system.ipc_shared_mem_size");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_shared_mem_size", NULL, "ipc shared memory", NULL, "IPC Shared Memory Segments Size", "kilobytes", 1000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "allocated", NULL, 1, 1024, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+            // --------------------------------------------------------------------
 
-                rrddim_set(st, "allocated", ipc_shm.segsize);
-                rrdset_done(st);
+            if (unlikely(!st_size)) {
+                st_size = rrdset_create_localhost("system",
+                                             "ipc_msq_size",
+                                             NULL,
+                                             "ipc message queues",
+                                             NULL,
+                                             "Size of IPC Message Queues",
+                                             "bytes",
+                                             1100,
+                                             update_every,
+                                             RRDSET_TYPE_LINE
+                );
+
+                rd_allocated = rrddim_add(st_size, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                rd_used = rrddim_add(st_size, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
             }
+            else rrdset_next(st_size);
+
+            rrddim_set_by_pointer(st_size, rd_allocated, ipc_msq.allocsize);
+            rrddim_set_by_pointer(st_size, rd_used, ipc_msq.usedsize);
+            rrdset_done(st_size);
         }
     }
 
-    // --------------------------------------------------------------------
-
-    if (likely(do_ipc_msg_queues)) {
-        if (unlikely(GETSYSCTL("kern.ipc.msgmni", ipc_msq.msgmni))) {
-            do_ipc_msg_queues = 0;
-            error("DISABLED: system.ipc_msq_queues");
-            error("DISABLED: system.ipc_msq_messages");
-            error("DISABLED: system.ipc_msq_size");
-        } else {
-            ipc_msq_data = reallocz(ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni);
-            if (unlikely(getsysctl("kern.ipc.msqids", ipc_msq_data, sizeof(struct msqid_kernel) * ipc_msq.msgmni))) {
-                do_ipc_msg_queues = 0;
-                error("DISABLED: system.ipc_msq_queues");
-                error("DISABLED: system.ipc_msq_messages");
-                error("DISABLED: system.ipc_msq_size");
-            } else {
-                for (i = 0; i < ipc_msq.msgmni; i++) {
-                    if (unlikely(ipc_msq_data[i].u.msg_qbytes != 0)) {
-                        ipc_msq.queues += 1;
-                        ipc_msq.messages += ipc_msq_data[i].u.msg_qnum;
-                        ipc_msq.usedsize += ipc_msq_data[i].u.msg_cbytes;
-                        ipc_msq.allocsize += ipc_msq_data[i].u.msg_qbytes;
-                    }
-                }
+    return 0;
+}
 
-                // --------------------------------------------------------------------
+// --------------------------------------------------------------------------------------------------------------------
+// uptime
 
-                st = rrdset_find_localhost("system.ipc_msq_queues");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_msq_queues", NULL, "ipc message queues", NULL, "Number of IPC Message Queues", "queues", 990, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "queues", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+int do_uptime(int update_every, usec_t dt) {
+    (void)dt;
+    struct timespec up_time;
 
-                rrddim_set(st, "queues", ipc_msq.queues);
-                rrdset_done(st);
+    clock_gettime(CLOCK_UPTIME, &up_time);
 
-                // --------------------------------------------------------------------
+    // --------------------------------------------------------------------
 
-                st = rrdset_find_localhost("system.ipc_msq_messages");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_msq_messages", NULL, "ipc message queues", NULL, "Number of Messages in IPC Message Queues", "messages", 1000, localhost->rrd_update_every, RRDSET_TYPE_AREA);
-                    rrddim_add(st, "messages", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+    static RRDSET *st = NULL;
+    static RRDDIM *rd = NULL;
+
+    if(unlikely(!st)) {
+        st = rrdset_create_localhost("system",
+                                     "uptime",
+                                     NULL,
+                                     "uptime",
+                                     NULL,
+                                     "System Uptime",
+                                     "seconds",
+                                     1000,
+                                     update_every,
+                                     RRDSET_TYPE_LINE
+        );
+
+        rd = rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+    }
+    else rrdset_next(st);
 
-                rrddim_set(st, "messages", ipc_msq.messages);
-                rrdset_done(st);
+    rrddim_set_by_pointer(st, rd, up_time.tv_sec);
+    rrdset_done(st);
 
-                // --------------------------------------------------------------------
+    return 0;
+}
 
-                st = rrdset_find_localhost("system.ipc_msq_size");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("system", "ipc_msq_size", NULL, "ipc message queues", NULL, "Size of IPC Message Queues", "bytes", 1100, localhost->rrd_update_every, RRDSET_TYPE_LINE);
-                    rrddim_add(st, "allocated", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                    rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                }
-                else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.isr
 
-                rrddim_set(st, "allocated", ipc_msq.allocsize);
-                rrddim_set(st, "used", ipc_msq.usedsize);
-                rrdset_done(st);
+int do_net_isr(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_netisr = -1, do_netisr_per_core = -1;
 
-            }
-        }
+    if (unlikely(do_netisr == -1)) {
+        do_netisr =          config_get_boolean("plugin:freebsd:net.isr", "netisr",          1);
+        do_netisr_per_core = config_get_boolean("plugin:freebsd:net.isr", "netisr per core", 1);
     }
 
-    // --------------------------------------------------------------------
+    static int mib_workstream[3] = {0, 0, 0}, mib_work[3] = {0, 0, 0};
+    int common_error = 0;
+    size_t netisr_workstream_size = sizeof(mib_workstream), netisr_work_size = sizeof(mib_work);
+    unsigned long num_netisr_workstreams = 0, num_netisr_works = 0;
+    static struct sysctl_netisr_workstream *netisr_workstream = NULL;
+    static struct sysctl_netisr_work *netisr_work = NULL;
+    static struct netisr_stats {
+        collected_number dispatched;
+        collected_number hybrid_dispatched;
+        collected_number qdrops;
+        collected_number queued;
+    } *netisr_stats = NULL;
 
     if (likely(do_netisr || do_netisr_per_core)) {
-        if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
-            common_error = 1;
-        } else if (unlikely(sysctlbyname("net.isr.workstream", NULL, &netisr_workstream_size, NULL, 0) == -1)) {
-            error("FREEBSD: sysctl(net.isr.workstream...) failed: %s", strerror(errno));
+        if (unlikely(GETSYSCTL_SIZE("net.isr.workstream", mib_workstream, netisr_workstream_size))) {
             common_error = 1;
-        } else if (unlikely(sysctlbyname("net.isr.work", NULL, &netisr_work_size, NULL, 0) == -1)) {
-            error("FREEBSD: sysctl(net.isr.work...) failed: %s", strerror(errno));
+        } else if (unlikely(GETSYSCTL_SIZE("net.isr.work", mib_work, netisr_work_size))) {
             common_error = 1;
         } else {
             num_netisr_workstreams = netisr_workstream_size / sizeof(struct sysctl_netisr_workstream);
             netisr_workstream = reallocz(netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream));
-            if (unlikely(getsysctl("net.isr.workstream", netisr_workstream, num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
+            if (unlikely(GETSYSCTL_WSIZE("net.isr.workstream", mib_workstream, netisr_workstream,
+                                           num_netisr_workstreams * sizeof(struct sysctl_netisr_workstream)))){
                 common_error = 1;
             } else {
                 num_netisr_works = netisr_work_size / sizeof(struct sysctl_netisr_work);
                 netisr_work = reallocz(netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work));
-                if (unlikely(getsysctl("net.isr.work", netisr_work, num_netisr_works * sizeof(struct sysctl_netisr_work)))){
+                if (unlikely(GETSYSCTL_WSIZE("net.isr.work", mib_work, netisr_work,
+                                               num_netisr_works * sizeof(struct sysctl_netisr_work)))){
                     common_error = 1;
                 }
             }
         }
         if (unlikely(common_error)) {
             do_netisr = 0;
-            error("DISABLED: system.softnet_stat");
+            error("DISABLED: system.softnet_stat chart");
             do_netisr_per_core = 0;
-            error("DISABLED: system.cpuX_softnet_stat");
+            error("DISABLED: system.cpuX_softnet_stat chart");
             common_error = 0;
+            error("DISABLED: net.isr module");
+            return 1;
         } else {
-            netisr_stats = reallocz(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
-            bzero(netisr_stats, (ncpus + 1) * sizeof(struct netisr_stats));
+            unsigned long i, n;
+            int j;
+
+            netisr_stats = reallocz(netisr_stats, (number_of_cpus + 1) * sizeof(struct netisr_stats));
+            memset(netisr_stats, 0, (number_of_cpus + 1) * sizeof(struct netisr_stats));
             for (i = 0; i < num_netisr_workstreams; i++) {
                 for (n = 0; n < num_netisr_works; n++) {
                     if (netisr_workstream[i].snws_wsid == netisr_work[n].snw_wsid) {
@@ -1117,376 +1314,402 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                     }
                 }
             }
-            for (i = 0; i < ncpus; i++) {
-                netisr_stats[ncpus].dispatched += netisr_stats[i].dispatched;
-                netisr_stats[ncpus].hybrid_dispatched += netisr_stats[i].hybrid_dispatched;
-                netisr_stats[ncpus].qdrops += netisr_stats[i].qdrops;
-                netisr_stats[ncpus].queued += netisr_stats[i].queued;
+            for (j = 0; j < number_of_cpus; j++) {
+                netisr_stats[number_of_cpus].dispatched += netisr_stats[j].dispatched;
+                netisr_stats[number_of_cpus].hybrid_dispatched += netisr_stats[j].hybrid_dispatched;
+                netisr_stats[number_of_cpus].qdrops += netisr_stats[j].qdrops;
+                netisr_stats[number_of_cpus].queued += netisr_stats[j].queued;
             }
         }
+    } else {
+        error("DISABLED: net.isr module");
+        return 1;
     }
 
     // --------------------------------------------------------------------
 
     if (likely(do_netisr)) {
-        st = rrdset_find_bytype_localhost("system", "softnet_stat");
+        static RRDSET *st = NULL;
+        static RRDDIM *rd_dispatched = NULL, *rd_hybrid_dispatched = NULL, *rd_qdrops = NULL, *rd_queued = NULL;
+
         if (unlikely(!st)) {
-            st = rrdset_create_localhost("system", "softnet_stat", NULL, "softnet_stat", NULL, "System softnet_stat", "events/s", 955, update_every, RRDSET_TYPE_LINE);
-            rrddim_add(st, "dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            rrddim_add(st, "qdrops", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-            rrddim_add(st, "queued", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            st = rrdset_create_localhost("system",
+                                         "softnet_stat",
+                                         NULL,
+                                         "softnet_stat",
+                                         NULL,
+                                         "System softnet_stat",
+                                         "events/s",
+                                         955,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rd_dispatched        = rrddim_add(st, "dispatched",        NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_hybrid_dispatched = rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_qdrops            = rrddim_add(st, "qdrops",            NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_queued            = rrddim_add(st, "queued",            NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
         else rrdset_next(st);
 
-        rrddim_set(st, "dispatched", netisr_stats[ncpus].dispatched);
-        rrddim_set(st, "hybrid_dispatched", netisr_stats[ncpus].hybrid_dispatched);
-        rrddim_set(st, "qdrops", netisr_stats[ncpus].qdrops);
-        rrddim_set(st, "queued", netisr_stats[ncpus].queued);
+        rrddim_set_by_pointer(st, rd_dispatched,        netisr_stats[number_of_cpus].dispatched);
+        rrddim_set_by_pointer(st, rd_hybrid_dispatched, netisr_stats[number_of_cpus].hybrid_dispatched);
+        rrddim_set_by_pointer(st, rd_qdrops,            netisr_stats[number_of_cpus].qdrops);
+        rrddim_set_by_pointer(st, rd_queued,            netisr_stats[number_of_cpus].queued);
         rrdset_done(st);
     }
 
     // --------------------------------------------------------------------
 
     if (likely(do_netisr_per_core)) {
-        for (i = 0; i < ncpus ;i++) {
-            snprintfz(netstat_cpuid, 21, "cpu%d_softnet_stat", i);
+        static struct softnet_chart {
+            char netisr_cpuid[MAX_INT_DIGITS + 17];
+            RRDSET *st;
+            RRDDIM *rd_dispatched;
+            RRDDIM *rd_hybrid_dispatched;
+            RRDDIM *rd_qdrops;
+            RRDDIM *rd_queued;
+        } *all_softnet_charts = NULL;
+        static int old_number_of_cpus = 0;
+        int i;
+
+        if(unlikely(number_of_cpus > old_number_of_cpus)) {
+            all_softnet_charts = reallocz(all_softnet_charts, sizeof(struct softnet_chart) * number_of_cpus);
+            memset(&all_softnet_charts[old_number_of_cpus], 0, sizeof(struct softnet_chart) * (number_of_cpus - old_number_of_cpus));
+            old_number_of_cpus = number_of_cpus;
+        }
 
-            st = rrdset_find_bytype_localhost("cpu", netstat_cpuid);
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("cpu", netstat_cpuid, NULL, "softnet_stat", NULL, "Per CPU netisr statistics", "events/s", 1101 + i, update_every, RRDSET_TYPE_LINE);
-                rrddim_add(st, "dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "hybrid_dispatched", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "qdrops", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "queued", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+        for (i = 0; i < number_of_cpus ;i++) {
+            snprintfz(all_softnet_charts[i].netisr_cpuid, MAX_INT_DIGITS + 17, "cpu%d_softnet_stat", i);
+
+            if (unlikely(!all_softnet_charts[i].st)) {
+                all_softnet_charts[i].st = rrdset_create_localhost("cpu",
+                                                                   all_softnet_charts[i].netisr_cpuid,
+                                                                   NULL,
+                                                                   "softnet_stat",
+                                                                   NULL,
+                                                                   "Per CPU netisr statistics",
+                                                                   "events/s",
+                                                                   1101 + i,
+                                                                   update_every,
+                                                                   RRDSET_TYPE_LINE
+                );
+
+                all_softnet_charts[i].rd_dispatched        = rrddim_add(all_softnet_charts[i].st, "dispatched",
+                                                                NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                all_softnet_charts[i].rd_hybrid_dispatched = rrddim_add(all_softnet_charts[i].st, "hybrid_dispatched",
+                                                                NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                all_softnet_charts[i].rd_qdrops            = rrddim_add(all_softnet_charts[i].st, "qdrops",
+                                                                NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                all_softnet_charts[i].rd_queued            = rrddim_add(all_softnet_charts[i].st, "queued",
+                                                                NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
             }
-            else rrdset_next(st);
-
-            rrddim_set(st, "dispatched", netisr_stats[i].dispatched);
-            rrddim_set(st, "hybrid_dispatched", netisr_stats[i].hybrid_dispatched);
-            rrddim_set(st, "qdrops", netisr_stats[i].qdrops);
-            rrddim_set(st, "queued", netisr_stats[i].queued);
-            rrdset_done(st);
+            else rrdset_next(all_softnet_charts[i].st);
+
+            rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_dispatched,
+                                  netisr_stats[i].dispatched);
+            rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_hybrid_dispatched,
+                                  netisr_stats[i].hybrid_dispatched);
+            rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_qdrops,
+                                  netisr_stats[i].qdrops);
+            rrddim_set_by_pointer(all_softnet_charts[i].st, all_softnet_charts[i].rd_queued,
+                                  netisr_stats[i].queued);
+            rrdset_done(all_softnet_charts[i].st);
         }
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
 
-    if (likely(do_bandwidth)) {
-        if (unlikely(getifaddrs(&ifap))) {
-            error("FREEBSD: getifaddrs()");
-            do_bandwidth = 0;
-            error("DISABLED: system.ipv4");
-        } else {
-            iftot.ift_ibytes = iftot.ift_obytes = 0;
-            for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-                if (ifa->ifa_addr->sa_family != AF_INET)
-                        continue;
-                iftot.ift_ibytes += IFA_DATA(ibytes);
-                iftot.ift_obytes += IFA_DATA(obytes);
-            }
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.states
 
-            st = rrdset_find_localhost("system.ipv4");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "ipv4", NULL, "network", NULL, "IPv4 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+int do_net_inet_tcp_states(int update_every, usec_t dt) {
+    (void)dt;
+    static int mib[4] = {0, 0, 0, 0};
+    uint64_t tcps_states[TCP_NSTATES];
 
-                rrddim_add(st, "InOctets", "received", 8, 1024, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "OutOctets", "sent", -8, 1024, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+    // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
+    if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.states", mib, tcps_states))) {
+        error("DISABLED: ipv4.tcpsock chart");
+        error("DISABLED: net.inet.tcp.states module");
+        return 1;
+    } else {
 
-            rrddim_set(st, "InOctets", iftot.ift_ibytes);
-            rrddim_set(st, "OutOctets", iftot.ift_obytes);
-            rrdset_done(st);
+        // --------------------------------------------------------------------
 
-            // --------------------------------------------------------------------
+        static RRDSET *st = NULL;
+        static RRDDIM *rd = NULL;
 
-            iftot.ift_ibytes = iftot.ift_obytes = 0;
-            for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-                if (ifa->ifa_addr->sa_family != AF_INET6)
-                        continue;
-                iftot.ift_ibytes += IFA_DATA(ibytes);
-                iftot.ift_obytes += IFA_DATA(obytes);
-            }
+        if (unlikely(!st)) {
+            st = rrdset_create_localhost("ipv4",
+                                         "tcpsock",
+                                         NULL,
+                                         "tcp",
+                                         NULL,
+                                         "IPv4 TCP Connections",
+                                         "active connections",
+                                         2500,
+                                         update_every,
+                                         RRDSET_TYPE_LINE
+            );
+
+            rd = rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+        } else
+            rrdset_next(st);
+
+        rrddim_set_by_pointer(st, rd, tcps_states[TCPS_ESTABLISHED]);
+        rrdset_done(st);
+    }
 
-            st = rrdset_find_localhost("system.ipv6");
-            if (unlikely(!st)) {
-                st = rrdset_create_localhost("system", "ipv6", NULL, "network", NULL, "IPv6 Bandwidth", "kilobits/s", 500, update_every, RRDSET_TYPE_AREA);
+    return 0;
+}
 
-                rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
-                rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.tcp.stats
+
+int do_net_inet_tcp_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_tcp_packets = -1, do_tcp_errors = -1, do_tcp_handshake = -1, do_tcpext_connaborts = -1, do_tcpext_ofo = -1, do_tcpext_syncookies = -1, do_ecn = -1;
+
+    if (unlikely(do_tcp_packets == -1)) {
+        do_tcp_packets       = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP packets",          1);
+        do_tcp_errors        = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP errors",           1);
+        do_tcp_handshake     = config_get_boolean("plugin:freebsd:net.inet.tcp.stats", "ipv4 TCP handshake issues", 1);
+        do_tcpext_connaborts = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP connection aborts",
+                                                           CONFIG_BOOLEAN_AUTO);
+        do_tcpext_ofo        = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP out-of-order queue",
+                                                           CONFIG_BOOLEAN_AUTO);
+        do_tcpext_syncookies = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "TCP SYN cookies",
+                                                           CONFIG_BOOLEAN_AUTO);
+        do_ecn               = config_get_boolean_ondemand("plugin:freebsd:net.inet.tcp.stats", "ECN packets",
+                                                           CONFIG_BOOLEAN_AUTO);
+    }
 
-            rrddim_set(st, "sent", iftot.ift_obytes);
-            rrddim_set(st, "received", iftot.ift_ibytes);
-            rrdset_done(st);
+    // 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_syncookies || do_ecn)) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct tcpstat tcpstat;
 
-            for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
-                if (ifa->ifa_addr->sa_family != AF_LINK)
-                        continue;
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet.tcp.stats", mib, tcpstat))) {
+            do_tcp_packets = 0;
+            error("DISABLED: ipv4.tcppackets chart");
+            do_tcp_errors = 0;
+            error("DISABLED: ipv4.tcperrors  chart");
+            do_tcp_handshake = 0;
+            error("DISABLED: ipv4.tcphandshake  chart");
+            do_tcpext_connaborts = 0;
+            error("DISABLED: ipv4.tcpconnaborts  chart");
+            do_tcpext_ofo = 0;
+            error("DISABLED: ipv4.tcpofo chart");
+            do_tcpext_syncookies = 0;
+            error("DISABLED: ipv4.tcpsyncookies chart");
+            do_ecn = 0;
+            error("DISABLED: ipv4.ecnpkts chart");
+            error("DISABLED: net.inet.tcp.stats module");
+            return 1;
+        } else {
 
-                // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
 
-                st = rrdset_find_bytype_localhost("net", ifa->ifa_name);
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("net", ifa->ifa_name, NULL, ifa->ifa_name, "net.net", "Bandwidth", "kilobits/s", 7000, update_every, RRDSET_TYPE_AREA);
+            if (likely(do_tcp_packets)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_segs = NULL, *rd_out_segs = NULL;
 
-                    rrddim_add(st, "received", NULL, 8, 1024, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -8, 1024, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcppackets",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "IPv4 TCP Packets",
+                                                 "packets/s",
+                                                 2600,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_segs  = rrddim_add(st, "InSegs",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_segs = rrddim_add(st, "OutSegs", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
 
-                rrddim_set(st, "received", IFA_DATA(ibytes));
-                rrddim_set(st, "sent", IFA_DATA(obytes));
+                rrddim_set_by_pointer(st, rd_in_segs,  tcpstat.tcps_rcvtotal);
+                rrddim_set_by_pointer(st, rd_out_segs, tcpstat.tcps_sndtotal);
                 rrdset_done(st);
+            }
 
-                // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
+
+            if (likely(do_tcp_errors)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_errs = NULL, *rd_in_csum_errs = NULL, *rd_retrans_segs = NULL;
 
-                st = rrdset_find_bytype_localhost("net_packets", ifa->ifa_name);
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("net_packets", ifa->ifa_name, NULL, ifa->ifa_name, "net.packets", "Packets", "packets/s", 7001, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcperrors",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "IPv4 TCP Errors",
+                                                 "packets/s",
+                                                 2700,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "multicast_received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "multicast_sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
+                    rd_in_errs      = rrddim_add(st, "InErrs",       NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_csum_errs = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_retrans_segs = rrddim_add(st, "RetransSegs",  NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
 
-                rrddim_set(st, "received", IFA_DATA(ipackets));
-                rrddim_set(st, "sent", IFA_DATA(opackets));
-                rrddim_set(st, "multicast_received", IFA_DATA(imcasts));
-                rrddim_set(st, "multicast_sent", IFA_DATA(omcasts));
+#if __FreeBSD__ >= 11
+                rrddim_set_by_pointer(st, rd_in_errs,      tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull +
+                                                           tcpstat.tcps_rcvshort);
+#else
+                rrddim_set_by_pointer(st, rd_in_errs,      tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
+#endif
+                rrddim_set_by_pointer(st, rd_in_csum_errs, tcpstat.tcps_rcvbadsum);
+                rrddim_set_by_pointer(st, rd_retrans_segs, tcpstat.tcps_sndrexmitpack);
                 rrdset_done(st);
+            }
 
-                // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
+
+            if (likely(do_tcp_handshake)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_estab_resets = NULL, *rd_active_opens = NULL, *rd_passive_opens = NULL,
+                              *rd_attempt_fails = NULL;
 
-                st = rrdset_find_bytype_localhost("net_errors", ifa->ifa_name);
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("net_errors", ifa->ifa_name, NULL, ifa->ifa_name, "net.errors", "Interface Errors", "errors/s", 7002, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcphandshake",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "IPv4 TCP Handshake Issues",
+                                                 "events/s",
+                                                 2900,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
+                    rd_estab_resets  = rrddim_add(st, "EstabResets",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_active_opens  = rrddim_add(st, "ActiveOpens",  NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_passive_opens = rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_attempt_fails = rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
 
-                rrddim_set(st, "inbound", IFA_DATA(ierrors));
-                rrddim_set(st, "outbound", IFA_DATA(oerrors));
+                rrddim_set_by_pointer(st, rd_estab_resets,  tcpstat.tcps_drops);
+                rrddim_set_by_pointer(st, rd_active_opens,  tcpstat.tcps_connattempt);
+                rrddim_set_by_pointer(st, rd_passive_opens, tcpstat.tcps_accepts);
+                rrddim_set_by_pointer(st, rd_attempt_fails, tcpstat.tcps_conndrops);
                 rrdset_done(st);
+            }
 
-                // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
 
-                st = rrdset_find_bytype_localhost("net_drops", ifa->ifa_name);
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("net_drops", ifa->ifa_name, NULL, ifa->ifa_name, "net.drops", "Interface Drops", "drops/s", 7003, update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+            if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
+                do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
 
-                    rrddim_add(st, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-#if __FreeBSD__ >= 11
-                    rrddim_add(st, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-#endif
-                }
-                else rrdset_next(st);
-
-                rrddim_set(st, "inbound", IFA_DATA(iqdrops));
-#if __FreeBSD__ >= 11
-                rrddim_set(st, "outbound", IFA_DATA(oqdrops));
-#endif
-                rrdset_done(st);
-
-                // --------------------------------------------------------------------
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_on_data = NULL, *rd_on_close = NULL, *rd_on_memory = NULL,
+                              *rd_on_timeout = NULL, *rd_on_linger = NULL;
 
-                st = rrdset_find_bytype_localhost("net_events", ifa->ifa_name);
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("net_events", ifa->ifa_name, NULL, ifa->ifa_name, "net.events", "Network Interface Events", "events/s", 7006, update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
-                    rrddim_add(st, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcpconnaborts",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "TCP Connection Aborts",
+                                                 "connections/s",
+                                                 3010,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_on_data    = rrddim_add(st, "TCPAbortOnData",    "baddata",     1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_on_close   = rrddim_add(st, "TCPAbortOnClose",   "userclosed",  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_on_memory  = rrddim_add(st, "TCPAbortOnMemory",  "nomemory",    1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_on_timeout = rrddim_add(st, "TCPAbortOnTimeout", "timeout",     1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_on_linger  = rrddim_add(st, "TCPAbortOnLinger",  "linger",      1, 1, RRD_ALGORITHM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "collisions", IFA_DATA(collisions));
-                rrdset_done(st);
-            }
-
-            freeifaddrs(ifap);
-        }
-    }
-
-    // --------------------------------------------------------------------
-
-    // see http://net-snmp.sourceforge.net/docs/mibs/tcp.html
-    if (likely(do_tcp_sockets)) {
-        if (unlikely(GETSYSCTL("net.inet.tcp.states", tcps_states))) {
-            do_tcp_sockets = 0;
-            error("DISABLED: ipv4.tcpsock");
-        } else {
-            if (likely(do_tcp_sockets)) {
-                st = rrdset_find_localhost("ipv4.tcpsock");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcpsock", NULL, "tcp", NULL, "IPv4 TCP Connections",
-                                       "active connections", 2500, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "CurrEstab", "connections", 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                } else
-                    rrdset_next(st);
-
-                rrddim_set(st, "CurrEstab", tcps_states[TCPS_ESTABLISHED]);
-                rrdset_done(st);
-            }
-        }
-    }
-
-    // --------------------------------------------------------------------
-
-    // 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_localhost("ipv4.tcppackets");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcppackets", NULL, "tcp", NULL, "IPv4 TCP Packets",
-                                       "packets/s",
-                                       2600, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "InSegs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutSegs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                } else
-                    rrdset_next(st);
-
-                rrddim_set(st, "InSegs", tcpstat.tcps_rcvtotal);
-                rrddim_set(st, "OutSegs", tcpstat.tcps_sndtotal);
+                rrddim_set_by_pointer(st, rd_on_data,    tcpstat.tcps_rcvpackafterwin);
+                rrddim_set_by_pointer(st, rd_on_close,   tcpstat.tcps_rcvafterclose);
+                rrddim_set_by_pointer(st, rd_on_memory,  tcpstat.tcps_rcvmemdrop);
+                rrddim_set_by_pointer(st, rd_on_timeout, tcpstat.tcps_persistdrop);
+                rrddim_set_by_pointer(st, rd_on_linger,  tcpstat.tcps_finwait2_drops);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
-            if (likely(do_tcp_errors)) {
-                st = rrdset_find_localhost("ipv4.tcperrors");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcperrors", NULL, "tcp", NULL, "IPv4 TCP Errors",
-                                       "packets/s",
-                                       2700, update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
-                    rrddim_add(st, "InErrs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "RetransSegs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                } else
-                    rrdset_next(st);
-
-#if __FreeBSD__ >= 11
-                rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvreassfull + tcpstat.tcps_rcvshort);
-#else
-                rrddim_set(st, "InErrs", tcpstat.tcps_rcvbadoff + tcpstat.tcps_rcvshort);
-#endif
-                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_localhost("ipv4.tcphandshake");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcphandshake", NULL, "tcp", NULL,
-                                       "IPv4 TCP Handshake Issues",
-                                       "events/s", 2900, update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
-
-                    rrddim_add(st, "EstabResets", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "ActiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "PassiveOpens", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "AttemptFails", NULL, 1, 1, RRD_ALGORITHM_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_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
+                do_tcpext_ofo = CONFIG_BOOLEAN_YES;
 
-            // --------------------------------------------------------------------
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ofo_queue = NULL;
 
-            if (do_tcpext_connaborts == CONFIG_BOOLEAN_YES || (do_tcpext_connaborts == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_rcvpackafterwin || tcpstat.tcps_rcvafterclose || tcpstat.tcps_rcvmemdrop || tcpstat.tcps_persistdrop || tcpstat.tcps_finwait2_drops))) {
-                do_tcpext_connaborts = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv4.tcpconnaborts");
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcpconnaborts", NULL, "tcp", NULL, "TCP Connection Aborts", "connections/s", 3010, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "TCPAbortOnData",    "baddata",     1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "TCPAbortOnClose",   "userclosed",  1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "TCPAbortOnMemory",  "nomemory",    1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "TCPAbortOnTimeout", "timeout",     1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "TCPAbortOnLinger",  "linger",      1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcpofo",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "TCP Out-Of-Order Queue",
+                                                 "packets/s",
+                                                 3050,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_ofo_queue = rrddim_add(st, "TCPOFOQueue", "inqueue",  1, 1, RRD_ALGORITHM_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);
-                rrddim_set(st, "TCPAbortOnLinger",  tcpstat.tcps_finwait2_drops);
+                rrddim_set_by_pointer(st, rd_ofo_queue,   tcpstat.tcps_rcvoopack);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
-            if (do_tcpext_ofo == CONFIG_BOOLEAN_YES || (do_tcpext_ofo == CONFIG_BOOLEAN_AUTO && tcpstat.tcps_rcvoopack)) {
-                do_tcpext_ofo = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv4.tcpofo");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcpofo", NULL, "tcp", NULL, "TCP Out-Of-Order Queue", "packets/s", 3050, update_every, RRDSET_TYPE_LINE);
+            if (do_tcpext_syncookies == CONFIG_BOOLEAN_YES || (do_tcpext_syncookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
+                do_tcpext_syncookies = CONFIG_BOOLEAN_YES;
 
-                    rrddim_add(st, "TCPOFOQueue", "inqueue",  1, 1, RRD_ALGORITHM_INCREMENTAL);
-                }
-                else rrdset_next(st);
-
-                rrddim_set(st, "TCPOFOQueue",   tcpstat.tcps_rcvoopack);
-                rrdset_done(st);
-            }
-
-            // --------------------------------------------------------------------
-
-            if (do_tcpext_syscookies == CONFIG_BOOLEAN_YES || (do_tcpext_syscookies == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_sc_sendcookie || tcpstat.tcps_sc_recvcookie || tcpstat.tcps_sc_zonefail))) {
-                do_tcpext_syscookies = CONFIG_BOOLEAN_YES;
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_recv = NULL, *rd_send = NULL, *rd_failed = NULL;
 
-                st = rrdset_find_localhost("ipv4.tcpsyncookies");
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "tcpsyncookies", NULL, "tcp", NULL, "TCP SYN Cookies", "packets/s", 3100, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "SyncookiesRecv",   "received",  1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "SyncookiesSent",   "sent",     -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "SyncookiesFailed", "failed",   -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "tcpsyncookies",
+                                                 NULL,
+                                                 "tcp",
+                                                 NULL,
+                                                 "TCP SYN Cookies",
+                                                 "packets/s",
+                                                 3100,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_recv   = rrddim_add(st, "SyncookiesRecv",   "received",  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_send   = rrddim_add(st, "SyncookiesSent",   "sent",     -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_failed = rrddim_add(st, "SyncookiesFailed", "failed",   -1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_recv,   tcpstat.tcps_sc_recvcookie);
+                rrddim_set_by_pointer(st, rd_send,   tcpstat.tcps_sc_sendcookie);
+                rrddim_set_by_pointer(st, rd_failed, tcpstat.tcps_sc_zonefail);
                 rrdset_done(st);
             }
 
@@ -1494,90 +1717,181 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
             if (do_ecn == CONFIG_BOOLEAN_YES || (do_ecn == CONFIG_BOOLEAN_AUTO && (tcpstat.tcps_ecn_ce || tcpstat.tcps_ecn_ect0 || tcpstat.tcps_ecn_ect1))) {
                 do_ecn = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv4.ecnpkts");
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ce = NULL, *rd_no_ect = NULL, *rd_ect0 = NULL, *rd_ect1 = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "ecnpkts", NULL, "ecn", NULL, "IPv4 ECN Statistics", "packets/s", 8700, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "ecnpkts",
+                                                 NULL,
+                                                 "ecn",
+                                                 NULL,
+                                                 "IPv4 ECN Statistics",
+                                                 "packets/s",
+                                                 8700,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ce     = rrddim_add(st, "InCEPkts", "CEP", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_no_ect = rrddim_add(st, "InNoECTPkts", "NoECTP", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ect0   = rrddim_add(st, "InECT0Pkts", "ECTP0", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ect1   = rrddim_add(st, "InECT1Pkts", "ECTP1", 1, 1, RRD_ALGORITHM_INCREMENTAL);
                 }
                 else rrdset_next(st);
 
-                rrddim_set(st, "InCEPkts", tcpstat.tcps_ecn_ce);
-                rrddim_set(st, "InNoECTPkts", tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 + tcpstat.tcps_ecn_ect1));
-                rrddim_set(st, "InECT0Pkts", tcpstat.tcps_ecn_ect0);
-                rrddim_set(st, "InECT1Pkts", tcpstat.tcps_ecn_ect1);
+                rrddim_set_by_pointer(st, rd_ce,     tcpstat.tcps_ecn_ce);
+                rrddim_set_by_pointer(st, rd_no_ect, tcpstat.tcps_ecn_ce - (tcpstat.tcps_ecn_ect0 +
+                                                                            tcpstat.tcps_ecn_ect1));
+                rrddim_set_by_pointer(st, rd_ect0,   tcpstat.tcps_ecn_ect0);
+                rrddim_set_by_pointer(st, rd_ect1,   tcpstat.tcps_ecn_ect1);
                 rrdset_done(st);
             }
 
         }
+    } else {
+        error("DISABLED: net.inet.tcp.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.udp.stats
+
+int do_net_inet_udp_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_udp_packets = -1, do_udp_errors = -1;
+
+    if (unlikely(do_udp_packets == -1)) {
+        do_udp_packets = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP packets", 1);
+        do_udp_errors  = config_get_boolean("plugin:freebsd:net.inet.udp.stats", "ipv4 UDP errors", 1);
+    }
 
     // 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))) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct udpstat udpstat;
+
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet.udp.stats", mib, udpstat))) {
             do_udp_packets = 0;
-            error("DISABLED: ipv4.udppackets");
+            error("DISABLED: ipv4.udppackets chart");
             do_udp_errors = 0;
-            error("DISABLED: ipv4.udperrors");
+            error("DISABLED: ipv4.udperrors chart");
+            error("DISABLED: net.inet.udp.stats module");
+            return 1;
         } else {
+
+            // --------------------------------------------------------------------
+
             if (likely(do_udp_packets)) {
-                st = rrdset_find_localhost("ipv4.udppackets");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "udppackets", NULL, "udp", NULL, "IPv4 UDP Packets",
-                                       "packets/s", 2601, update_every, RRDSET_TYPE_LINE);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL;
 
-                    rrddim_add(st, "InDatagrams", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutDatagrams", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv4",
+                                                 "udppackets",
+                                                 NULL,
+                                                 "udp",
+                                                 NULL,
+                                                 "IPv4 UDP Packets",
+                                                 "packets/s",
+                                                 2601,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in  = rrddim_add(st, "InDatagrams",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out = rrddim_add(st, "OutDatagrams", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
                 } else
                     rrdset_next(st);
 
-                rrddim_set(st, "InDatagrams", udpstat.udps_ipackets);
-                rrddim_set(st, "OutDatagrams", udpstat.udps_opackets);
+                rrddim_set_by_pointer(st, rd_in,  udpstat.udps_ipackets);
+                rrddim_set_by_pointer(st, rd_out, udpstat.udps_opackets);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_udp_errors)) {
-                st = rrdset_find_localhost("ipv4.udperrors");
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_errors = NULL, *rd_no_ports = NULL, *rd_recv_buf_errors = NULL,
+                              *rd_in_csum_errors = NULL, *rd_ignored_multi = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "udperrors", NULL, "udp", NULL, "IPv4 UDP Errors", "events/s",
-                                       2701, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "udperrors",
+                                                 NULL,
+                                                 "udp",
+                                                 NULL,
+                                                 "IPv4 UDP Errors",
+                                                 "events/s",
+                                                 2701,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "NoPorts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_errors       = rrddim_add(st, "InErrors",     NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_no_ports        = rrddim_add(st, "NoPorts",      NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_recv_buf_errors = rrddim_add(st, "RcvbufErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_csum_errors  = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ignored_multi   = rrddim_add(st, "IgnoredMulti", NULL, 1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_in_errors,       udpstat.udps_hdrops + udpstat.udps_badlen);
+                rrddim_set_by_pointer(st, rd_no_ports,        udpstat.udps_noport);
+                rrddim_set_by_pointer(st, rd_recv_buf_errors, udpstat.udps_fullsock);
+                rrddim_set_by_pointer(st, rd_in_csum_errors,  udpstat.udps_badsum + udpstat.udps_nosum);
+                rrddim_set_by_pointer(st, rd_ignored_multi,   udpstat.udps_filtermcast);
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: net.inet.udp.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.icmp.stats
+
+int do_net_inet_icmp_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_icmp_packets = -1, do_icmp_errors = -1, do_icmpmsg = -1;
+
+    if (unlikely(do_icmp_packets == -1)) {
+        do_icmp_packets = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP packets",  1);
+        do_icmp_errors  = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP errors",   1);
+        do_icmpmsg      = config_get_boolean("plugin:freebsd:net.inet.icmp.stats", "ipv4 ICMP messages", 1);
+    }
 
-    if (likely(do_icmp_packets || do_icmpmsg)) {
-        if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+    if (likely(do_icmp_packets || do_icmp_errors || do_icmpmsg)) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct icmpstat icmpstat;
+        int i;
+        struct icmp_total {
+            u_long  msgs_in;
+            u_long  msgs_out;
+        } icmp_total = {0, 0};
+
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet.icmp.stats", mib, icmpstat))) {
             do_icmp_packets = 0;
-            error("DISABLED: ipv4.icmp");
-            error("DISABLED: ipv4.icmp_errors");
+            error("DISABLED: ipv4.icmp chart");
+            do_icmp_errors = 0;
+            error("DISABLED: ipv4.icmp_errors chart");
             do_icmpmsg = 0;
-            error("DISABLED: ipv4.icmpmsg");
+            error("DISABLED: ipv4.icmpmsg chart");
+            error("DISABLED: net.inet.icmp.stats module");
+            return 1;
         } else {
             for (i = 0; i <= ICMP_MAXTYPE; i++) {
                 icmp_total.msgs_in += icmpstat.icps_inhist[i];
@@ -1588,39 +1902,54 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
             // --------------------------------------------------------------------
 
             if (likely(do_icmp_packets)) {
-                st = rrdset_find_localhost("ipv4.icmp");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "icmp", NULL, "icmp", NULL, "IPv4 ICMP Packets", "packets/s",
-                                       2602,
-                                       update_every, RRDSET_TYPE_LINE);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL;
 
-                    rrddim_add(st, "InMsgs", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutMsgs", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv4",
+                                                 "icmp",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv4 ICMP Packets",
+                                                 "packets/s",
+                                                 2602,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in  = rrddim_add(st, "InMsgs",  "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out = rrddim_add(st, "OutMsgs", "sent",    -1, 1, RRD_ALGORITHM_INCREMENTAL);
                 } else
                     rrdset_next(st);
 
-                rrddim_set(st, "InMsgs", icmp_total.msgs_in);
-                rrddim_set(st, "OutMsgs", icmp_total.msgs_out);
+                rrddim_set_by_pointer(st, rd_in,  icmp_total.msgs_in);
+                rrddim_set_by_pointer(st, rd_out, icmp_total.msgs_out);
 
                 rrdset_done(st);
+            }
 
-                // --------------------------------------------------------------------
+            // --------------------------------------------------------------------
+
+            if (likely(do_icmp_errors)) {
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_csum = NULL;
 
-                st = rrdset_find_localhost("ipv4.icmp_errors");
                 if (unlikely(!st)) {
                     st = rrdset_create_localhost("ipv4", "icmp_errors", NULL, "icmp", NULL, "IPv4 ICMP Errors",
-                                       "packets/s",
-                                       2603, update_every, RRDSET_TYPE_LINE);
+                                                 "packets/s",
+                                                 2603, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in      = rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out     = rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_csum = rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_in,      icmpstat.icps_badcode + icmpstat.icps_badlen +
+                                                      icmpstat.icps_checksum + icmpstat.icps_tooshort);
+                rrddim_set_by_pointer(st, rd_out,     icmpstat.icps_error);
+                rrddim_set_by_pointer(st, rd_in_csum, icmpstat.icps_checksum);
 
                 rrdset_done(st);
             }
@@ -1628,220 +1957,364 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
             // --------------------------------------------------------------------
 
             if (likely(do_icmpmsg)) {
-                st = rrdset_find_localhost("ipv4.icmpmsg");
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_reps = NULL, *rd_out_reps = NULL, *rd_in = NULL, *rd_out = NULL;
+
                 if (unlikely(!st)) {
                     st = rrdset_create_localhost("ipv4", "icmpmsg", NULL, "icmp", NULL, "IPv4 ICMP Messsages",
-                                       "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
+                                                 "packets/s", 2604, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InEchoReps", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_reps  = rrddim_add(st, "InEchoReps",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_reps = rrddim_add(st, "OutEchoReps", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in       = rrddim_add(st, "InEchos",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out      = rrddim_add(st, "OutEchos",    NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in_reps, icmpstat.icps_inhist[ICMP_ECHOREPLY]);
+                rrddim_set_by_pointer(st, rd_out_reps, icmpstat.icps_outhist[ICMP_ECHOREPLY]);
+                rrddim_set_by_pointer(st, rd_in, icmpstat.icps_inhist[ICMP_ECHO]);
+                rrddim_set_by_pointer(st, rd_out, icmpstat.icps_outhist[ICMP_ECHO]);
 
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: net.inet.icmp.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet.ip.stats
+
+int do_net_inet_ip_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_ip_packets = -1, do_ip_fragsout = -1, do_ip_fragsin = -1, do_ip_errors = -1;
+
+    if (unlikely(do_ip_packets == -1)) {
+        do_ip_packets  = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 packets", 1);
+        do_ip_fragsout = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments sent", 1);
+        do_ip_fragsin  = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 fragments assembly", 1);
+        do_ip_errors   = config_get_boolean("plugin:freebsd:net.inet.ip.stats", "ipv4 errors", 1);
+    }
 
     // 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))) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct ipstat ipstat;
+
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet.ip.stats", mib, ipstat))) {
             do_ip_packets = 0;
-            error("DISABLED: ipv4.packets");
+            error("DISABLED: ipv4.packets chart");
             do_ip_fragsout = 0;
-            error("DISABLED: ipv4.fragsout");
+            error("DISABLED: ipv4.fragsout chart");
             do_ip_fragsin = 0;
-            error("DISABLED: ipv4.fragsin");
+            error("DISABLED: ipv4.fragsin chart");
             do_ip_errors = 0;
-            error("DISABLED: ipv4.errors");
+            error("DISABLED: ipv4.errors chart");
+            error("DISABLED: net.inet.ip.stats module");
+            return 1;
         } else {
+
+            // --------------------------------------------------------------------
+
             if (likely(do_ip_packets)) {
-                st = rrdset_find_localhost("ipv4.packets");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "packets", NULL, "packets", NULL, "IPv4 Packets", "packets/s",
-                                       3000, update_every, RRDSET_TYPE_LINE);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_receives = NULL, *rd_out_requests = NULL, *rd_forward_datagrams = NULL,
+                              *rd_in_delivers = NULL;
 
-                    rrddim_add(st, "InReceives", "received", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutRequests", "sent", -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InDelivers", "delivered", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv4",
+                                                 "packets",
+                                                 NULL,
+                                                 "packets",
+                                                 NULL,
+                                                 "IPv4 Packets",
+                                                 "packets/s",
+                                                 3000,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_receives       = rrddim_add(st, "InReceives",    "received",  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_requests      = rrddim_add(st, "OutRequests",   "sent",     -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_forward_datagrams = rrddim_add(st, "ForwDatagrams", "forwarded", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_delivers       = rrddim_add(st, "InDelivers",    "delivered", 1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_in_receives,       ipstat.ips_total);
+                rrddim_set_by_pointer(st, rd_out_requests,      ipstat.ips_localout);
+                rrddim_set_by_pointer(st, rd_forward_datagrams, ipstat.ips_forward);
+                rrddim_set_by_pointer(st, rd_in_delivers,       ipstat.ips_delivered);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_ip_fragsout)) {
-                st = rrdset_find_localhost("ipv4.fragsout");
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ok = NULL, *rd_fails = NULL, *rd_created = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "fragsout", NULL, "fragments", NULL, "IPv4 Fragments Sent",
-                                       "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "fragsout",
+                                                 NULL,
+                                                 "fragments",
+                                                 NULL,
+                                                 "IPv4 Fragments Sent",
+                                                 "packets/s",
+                                                 3010,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "FragOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "FragFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ok      = rrddim_add(st, "FragOKs",     "ok",      1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_fails   = rrddim_add(st, "FragFails",   "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_created = rrddim_add(st, "FragCreates", "created", 1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_ok,      ipstat.ips_fragmented);
+                rrddim_set_by_pointer(st, rd_fails,   ipstat.ips_cantfrag);
+                rrddim_set_by_pointer(st, rd_created, ipstat.ips_ofragments);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_ip_fragsin)) {
-                st = rrdset_find_localhost("ipv4.fragsin");
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "fragsin", NULL, "fragments", NULL,
-                                       "IPv4 Fragments Reassembly",
-                                       "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv4",
+                                                 "fragsin",
+                                                 NULL,
+                                                 "fragments",
+                                                 NULL,
+                                                 "IPv4 Fragments Reassembly",
+                                                 "packets/s",
+                                                 3011,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "ReasmOKs", "ok", 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "ReasmReqds", "all", 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ok     = rrddim_add(st, "ReasmOKs",   "ok",      1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_failed = rrddim_add(st, "ReasmFails", "failed", -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_all    = rrddim_add(st, "ReasmReqds", "all",     1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_ok,     ipstat.ips_fragments);
+                rrddim_set_by_pointer(st, rd_failed, ipstat.ips_fragdropped);
+                rrddim_set_by_pointer(st, rd_all,    ipstat.ips_reassembled);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (likely(do_ip_errors)) {
-                st = rrdset_find_localhost("ipv4.errors");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv4", "errors", NULL, "errors", NULL, "IPv4 Errors", "packets/s",
-                                       3002,
-                                       update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+                              *rd_in_hdr_errors = NULL, *rd_out_no_routes = NULL,
+                              *rd_in_addr_errors = NULL, *rd_in_unknown_protos = NULL;
 
-                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv4",
+                                                 "errors",
+                                                 NULL,
+                                                 "errors",
+                                                 NULL,
+                                                 "IPv4 Errors",
+                                                 "packets/s",
+                                                 3002,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
 
-                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InUnknownProtos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_discards       = rrddim_add(st, "InDiscards",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_discards      = rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_hdr_errors     = rrddim_add(st, "InHdrErrors",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_no_routes     = rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_addr_errors    = rrddim_add(st, "InAddrErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_unknown_protos = rrddim_add(st, "InUnknownProtos", NULL,  1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_in_discards,       ipstat.ips_badsum + ipstat.ips_tooshort +
+                                                                ipstat.ips_toosmall + ipstat.ips_toolong);
+                rrddim_set_by_pointer(st, rd_out_discards,      ipstat.ips_odropped);
+                rrddim_set_by_pointer(st, rd_in_hdr_errors,     ipstat.ips_badhlen + ipstat.ips_badlen +
+                                                                ipstat.ips_badoptions + ipstat.ips_badvers);
+                rrddim_set_by_pointer(st, rd_out_no_routes,     ipstat.ips_noroute);
+                rrddim_set_by_pointer(st, rd_in_addr_errors,    ipstat.ips_badaddr);
+                rrddim_set_by_pointer(st, rd_in_unknown_protos, ipstat.ips_noproto);
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: net.inet.ip.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.ip6.stats
+
+int do_net_inet6_ip6_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int do_ip6_packets = -1, do_ip6_fragsout = -1, do_ip6_fragsin = -1, do_ip6_errors = -1;
+
+    if (unlikely(do_ip6_packets == -1)) {
+        do_ip6_packets  = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 packets",
+                                                      CONFIG_BOOLEAN_AUTO);
+        do_ip6_fragsout = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments sent",
+                                                      CONFIG_BOOLEAN_AUTO);
+        do_ip6_fragsin  = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 fragments assembly",
+                                                      CONFIG_BOOLEAN_AUTO);
+        do_ip6_errors   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.ip6.stats", "ipv6 errors",
+                                                      CONFIG_BOOLEAN_AUTO);
+    }
 
     if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
-        if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct ip6stat ip6stat;
+
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet6.ip6.stats", mib, ip6stat))) {
             do_ip6_packets = 0;
-            error("DISABLED: ipv6.packets");
+            error("DISABLED: ipv6.packets chart");
             do_ip6_fragsout = 0;
-            error("DISABLED: ipv6.fragsout");
+            error("DISABLED: ipv6.fragsout chart");
             do_ip6_fragsin = 0;
-            error("DISABLED: ipv6.fragsin");
+            error("DISABLED: ipv6.fragsin chart");
             do_ip6_errors = 0;
-            error("DISABLED: ipv6.errors");
+            error("DISABLED: ipv6.errors chart");
+            error("DISABLED: net.inet6.ip6.stats module");
+            return 1;
         } else {
+
+            // --------------------------------------------------------------------
+
             if (do_ip6_packets == CONFIG_BOOLEAN_YES || (do_ip6_packets == CONFIG_BOOLEAN_AUTO &&
-                                                          (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
-                                                           ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
+                                                         (ip6stat.ip6s_localout || ip6stat.ip6s_total ||
+                                                          ip6stat.ip6s_forward || ip6stat.ip6s_delivered))) {
                 do_ip6_packets = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.packets");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "packets", NULL, "packets", NULL, "IPv6 Packets", "packets/s", 3000,
-                                       update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "forwarded", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "delivers", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_received = NULL, *rd_sent = NULL, *rd_forwarded = NULL, *rd_delivers = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "packets",
+                                                 NULL,
+                                                 "packets",
+                                                 NULL,
+                                                 "IPv6 Packets",
+                                                 "packets/s",
+                                                 3000,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_received  = rrddim_add(st, "received",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_sent      = rrddim_add(st, "sent",      NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_forwarded = rrddim_add(st, "forwarded", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_delivers  = rrddim_add(st, "delivers",  NULL, -1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_sent,      ip6stat.ip6s_localout);
+                rrddim_set_by_pointer(st, rd_received,  ip6stat.ip6s_total);
+                rrddim_set_by_pointer(st, rd_forwarded, ip6stat.ip6s_forward);
+                rrddim_set_by_pointer(st, rd_delivers,  ip6stat.ip6s_delivered);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_ip6_fragsout == CONFIG_BOOLEAN_YES || (do_ip6_fragsout == CONFIG_BOOLEAN_AUTO &&
-                                                           (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
-                                                            ip6stat.ip6s_ofragments))) {
+                                                          (ip6stat.ip6s_fragmented || ip6stat.ip6s_cantfrag ||
+                                                           ip6stat.ip6s_ofragments))) {
                 do_ip6_fragsout = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.fragsout");
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_all = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "fragsout", NULL, "fragments", NULL, "IPv6 Fragments Sent",
-                                       "packets/s", 3010, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv6",
+                                                 "fragsout",
+                                                 NULL,
+                                                 "fragments",
+                                                 NULL,
+                                                 "IPv6 Fragments Sent",
+                                                 "packets/s",
+                                                 3010,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ok     = rrddim_add(st, "ok",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_failed = rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_all    = rrddim_add(st, "all",    NULL,  1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_ok,     ip6stat.ip6s_fragmented);
+                rrddim_set_by_pointer(st, rd_failed, ip6stat.ip6s_cantfrag);
+                rrddim_set_by_pointer(st, rd_all,    ip6stat.ip6s_ofragments);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_ip6_fragsin == CONFIG_BOOLEAN_YES || (do_ip6_fragsin == CONFIG_BOOLEAN_AUTO &&
-                                                          (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
-                                                           ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
+                                                         (ip6stat.ip6s_reassembled || ip6stat.ip6s_fragdropped ||
+                                                          ip6stat.ip6s_fragtimeout || ip6stat.ip6s_fragments))) {
                 do_ip6_fragsin = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.fragsin");
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_ok = NULL, *rd_failed = NULL, *rd_timeout = NULL, *rd_all = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "fragsin", NULL, "fragments", NULL, "IPv6 Fragments Reassembly",
-                                       "packets/s", 3011, update_every, RRDSET_TYPE_LINE);
+                    st = rrdset_create_localhost("ipv6",
+                                                 "fragsin",
+                                                 NULL,
+                                                 "fragments",
+                                                 NULL,
+                                                 "IPv6 Fragments Reassembly",
+                                                 "packets/s",
+                                                 3011,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
                     rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "ok", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "failed", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "all", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_ok      = rrddim_add(st, "ok",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_failed  = rrddim_add(st, "failed",  NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_timeout = rrddim_add(st, "timeout", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_all     = rrddim_add(st, "all",     NULL,  1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_ok,      ip6stat.ip6s_reassembled);
+                rrddim_set_by_pointer(st, rd_failed,  ip6stat.ip6s_fragdropped);
+                rrddim_set_by_pointer(st, rd_timeout, ip6stat.ip6s_fragtimeout);
+                rrddim_set_by_pointer(st, rd_all,     ip6stat.ip6s_fragments);
                 rrdset_done(st);
             }
 
@@ -1858,65 +2331,144 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
                     ip6stat.ip6s_cantforward ||
                     ip6stat.ip6s_noroute))) {
                 do_ip6_errors = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.errors");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "errors", NULL, "errors", NULL, "IPv6 Errors", "packets/s", 3002,
-                                       update_every, RRDSET_TYPE_LINE);
-                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
 
-                    rrddim_add(st, "InDiscards", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutDiscards", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_discards = NULL, *rd_out_discards = NULL,
+                              *rd_in_hdr_errors = NULL, *rd_in_addr_errors = NULL, *rd_in_truncated_pkts = NULL,
+                              *rd_in_no_routes = NULL, *rd_out_no_routes = NULL;
 
-                    rrddim_add(st, "InHdrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InAddrErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InTruncatedPkts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InNoRoutes", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "errors",
+                                                 NULL,
+                                                 "errors",
+                                                 NULL,
+                                                 "IPv6 Errors",
+                                                 "packets/s",
+                                                 3002,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
 
-                    rrddim_add(st, "OutNoRoutes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rrdset_flag_set(st, RRDSET_FLAG_DETAIL);
+
+                    rd_in_discards       = rrddim_add(st, "InDiscards",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_discards      = rrddim_add(st, "OutDiscards",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_hdr_errors     = rrddim_add(st, "InHdrErrors",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_addr_errors    = rrddim_add(st, "InAddrErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_truncated_pkts = rrddim_add(st, "InTruncatedPkts", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_no_routes      = rrddim_add(st, "InNoRoutes",      NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_no_routes     = rrddim_add(st, "OutNoRoutes",     NULL, -1, 1, RRD_ALGORITHM_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);
+                rrddim_set_by_pointer(st, rd_in_discards,       ip6stat.ip6s_toosmall);
+                rrddim_set_by_pointer(st, rd_out_discards,      ip6stat.ip6s_odropped);
+                rrddim_set_by_pointer(st, rd_in_hdr_errors,     ip6stat.ip6s_badoptions + ip6stat.ip6s_badvers +
+                                                                ip6stat.ip6s_exthdrtoolong);
+                rrddim_set_by_pointer(st, rd_in_addr_errors,    ip6stat.ip6s_sources_none);
+                rrddim_set_by_pointer(st, rd_in_truncated_pkts, ip6stat.ip6s_tooshort);
+                rrddim_set_by_pointer(st, rd_in_no_routes,      ip6stat.ip6s_cantforward);
+                rrddim_set_by_pointer(st, rd_out_no_routes,     ip6stat.ip6s_noroute);
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: net.inet6.ip6.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// net.inet6.icmp6.stats
+
+int do_net_inet6_icmp6_stats(int update_every, usec_t dt) {
+    (void)dt;
+    static int 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_icmp6 == -1)) {
+        do_icmp6          = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_redir    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp redirects",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_errors   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp errors",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_echos    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp echos",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_router   = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp router",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_neighbor = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp neighbor",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_icmp6_types    = config_get_boolean_ondemand("plugin:freebsd:net.inet6.icmp6.stats", "icmp types",
+                                                        CONFIG_BOOLEAN_AUTO);
+    }
 
     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))) {
+        static int mib[4] = {0, 0, 0, 0};
+        struct icmp6stat icmp6stat;
+
+        if (unlikely(GETSYSCTL_SIMPLE("net.inet6.icmp6.stats", mib, icmp6stat))) {
             do_icmp6 = 0;
-            error("DISABLED: ipv6.icmp");
+            error("DISABLED: ipv6.icmp chart");
+            do_icmp6_redir = 0;
+            error("DISABLED: ipv6.icmpredir chart");
+            do_icmp6_errors = 0;
+            error("DISABLED: ipv6.icmperrors chart");
+            do_icmp6_echos = 0;
+            error("DISABLED: ipv6.icmpechos chart");
+            do_icmp6_router = 0;
+            error("DISABLED: ipv6.icmprouter chart");
+            do_icmp6_neighbor = 0;
+            error("DISABLED: ipv6.icmpneighbor chart");
+            do_icmp6_types = 0;
+            error("DISABLED: ipv6.icmptypes chart");
+            error("DISABLED: net.inet6.icmp6.stats module");
+            return 1;
         } else {
+            int i;
+            struct icmp6_total {
+                u_long  msgs_in;
+                u_long  msgs_out;
+            } icmp6_total = {0, 0};
+
             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_BOOLEAN_YES || (do_icmp6 == CONFIG_BOOLEAN_AUTO && (icmp6_total.msgs_in || icmp6_total.msgs_out))) {
                 do_icmp6 = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmp");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmp", NULL, "icmp", NULL, "IPv6 ICMP Messages",
-                                       "messages/s", 10000, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmp",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 ICMP Messages",
+                                                 "messages/s",
+                                                 10000,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_received = rrddim_add(st, "received", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_sent     = rrddim_add(st, "sent",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
                 } else
                     rrdset_next(st);
 
-                rrddim_set(st, "sent", icmp6_total.msgs_in);
-                rrddim_set(st, "received", icmp6_total.msgs_out);
+                rrddim_set_by_pointer(st, rd_received, icmp6_total.msgs_out);
+                rrddim_set_by_pointer(st, rd_sent,     icmp6_total.msgs_in);
+
                 rrdset_done(st);
             }
 
@@ -1924,274 +2476,1488 @@ int do_freebsd_sysctl(int update_every, usec_t dt) {
 
             if (do_icmp6_redir == CONFIG_BOOLEAN_YES || (do_icmp6_redir == CONFIG_BOOLEAN_AUTO && (icmp6stat.icp6s_inhist[ND_REDIRECT] || icmp6stat.icp6s_outhist[ND_REDIRECT]))) {
                 do_icmp6_redir = CONFIG_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmpredir");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmpredir", NULL, "icmp", NULL, "IPv6 ICMP Redirects",
-                                       "redirects/s", 10050, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_received = NULL, *rd_sent = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmpredir",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 ICMP Redirects",
+                                                 "redirects/s",
+                                                 10050,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_received = rrddim_add(st, "received", NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_sent     = rrddim_add(st, "sent",     NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
                 } else
                     rrdset_next(st);
 
-                rrddim_set(st, "sent", icmp6stat.icp6s_inhist[ND_REDIRECT]);
-                rrddim_set(st, "received", icmp6stat.icp6s_outhist[ND_REDIRECT]);
+                rrddim_set_by_pointer(st, rd_received, icmp6stat.icp6s_outhist[ND_REDIRECT]);
+                rrddim_set_by_pointer(st, rd_sent, icmp6stat.icp6s_inhist[ND_REDIRECT]);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_icmp6_errors == CONFIG_BOOLEAN_YES || (do_icmp6_errors == CONFIG_BOOLEAN_AUTO && (
-                                                                            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]))) {
+                    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_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmperrors");
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_errors = NULL, *rd_out_errors = NULL, *rd_in_csum_errors = NULL,
+                              *rd_in_dest_unreachs = NULL, *rd_in_pkt_too_bigs = NULL, *rd_in_time_excds = NULL,
+                              *rd_in_parm_problems = NULL, *rd_out_dest_unreachs = NULL, *rd_out_time_excds = NULL,
+                              *rd_out_parm_problems = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmperrors", NULL, "icmp", NULL, "IPv6 ICMP Errors", "errors/s", 10100, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "InErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutErrors", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-
-                    rrddim_add(st, "InCsumErrors", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InDestUnreachs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InPktTooBigs", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InTimeExcds", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InParmProblems", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutTimeExcds", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmperrors",
+                                                 NULL, "icmp",
+                                                 NULL,
+                                                 "IPv6 ICMP Errors",
+                                                 "errors/s",
+                                                 10100,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_errors         = rrddim_add(st, "InErrors",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_errors        = rrddim_add(st, "OutErrors",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_csum_errors    = rrddim_add(st, "InCsumErrors",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_dest_unreachs  = rrddim_add(st, "InDestUnreachs",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_pkt_too_bigs   = rrddim_add(st, "InPktTooBigs",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_time_excds     = rrddim_add(st, "InTimeExcds",     NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_parm_problems  = rrddim_add(st, "InParmProblems",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_dest_unreachs = rrddim_add(st, "OutDestUnreachs", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_time_excds    = rrddim_add(st, "OutTimeExcds",    NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_parm_problems = rrddim_add(st, "OutParmProblems", NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in_errors,         icmp6stat.icp6s_badcode + icmp6stat.icp6s_badlen +
+                                                                icmp6stat.icp6s_checksum + icmp6stat.icp6s_tooshort);
+                rrddim_set_by_pointer(st, rd_out_errors,        icmp6stat.icp6s_error);
+                rrddim_set_by_pointer(st, rd_in_csum_errors,    icmp6stat.icp6s_checksum);
+                rrddim_set_by_pointer(st, rd_in_dest_unreachs,  icmp6stat.icp6s_inhist[ICMP6_DST_UNREACH]);
+                rrddim_set_by_pointer(st, rd_in_pkt_too_bigs,   icmp6stat.icp6s_badlen);
+                rrddim_set_by_pointer(st, rd_in_time_excds,     icmp6stat.icp6s_inhist[ICMP6_TIME_EXCEEDED]);
+                rrddim_set_by_pointer(st, rd_in_parm_problems,  icmp6stat.icp6s_inhist[ICMP6_PARAM_PROB]);
+                rrddim_set_by_pointer(st, rd_out_dest_unreachs, icmp6stat.icp6s_outhist[ICMP6_DST_UNREACH]);
+                rrddim_set_by_pointer(st, rd_out_time_excds,    icmp6stat.icp6s_outhist[ICMP6_TIME_EXCEEDED]);
+                rrddim_set_by_pointer(st, rd_out_parm_problems, icmp6stat.icp6s_outhist[ICMP6_PARAM_PROB]);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_icmp6_echos == CONFIG_BOOLEAN_YES || (do_icmp6_echos == CONFIG_BOOLEAN_AUTO && (
-                                                                 icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST] ||
-                                                                 icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST] ||
-                                                                 icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY] ||
-                                                                 icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]))) {
+                    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_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmpechos");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmpechos", NULL, "icmp", NULL, "IPv6 ICMP Echo", "messages/s", 10200, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InEchos", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutEchos", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InEchoReplies", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL, *rd_in_replies = NULL, *rd_out_replies = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmpechos",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 ICMP Echo",
+                                                 "messages/s",
+                                                 10200,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in          = rrddim_add(st, "InEchos",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out         = rrddim_add(st, "OutEchos",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_replies  = rrddim_add(st, "InEchoReplies",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_replies = rrddim_add(st, "OutEchoReplies", NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in,          icmp6stat.icp6s_inhist[ICMP6_ECHO_REQUEST]);
+                rrddim_set_by_pointer(st, rd_out,         icmp6stat.icp6s_outhist[ICMP6_ECHO_REQUEST]);
+                rrddim_set_by_pointer(st, rd_in_replies,  icmp6stat.icp6s_inhist[ICMP6_ECHO_REPLY]);
+                rrddim_set_by_pointer(st, rd_out_replies, icmp6stat.icp6s_outhist[ICMP6_ECHO_REPLY]);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_icmp6_router == CONFIG_BOOLEAN_YES || (do_icmp6_router == CONFIG_BOOLEAN_AUTO && (
-                                                                    icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT] ||
-                                                                    icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT] ||
-                                                                    icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT] ||
-                                                                    icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]))) {
+                    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_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmprouter");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmprouter", NULL, "icmp", NULL, "IPv6 Router Messages", "messages/s", 10400, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+                              *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmprouter",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 Router Messages",
+                                                 "messages/s",
+                                                 10400,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_solicits        = rrddim_add(st, "InSolicits",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_solicits       = rrddim_add(st, "OutSolicits",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_advertisements  = rrddim_add(st, "InAdvertisements",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in_solicits,        icmp6stat.icp6s_inhist[ND_ROUTER_SOLICIT]);
+                rrddim_set_by_pointer(st, rd_out_solicits,       icmp6stat.icp6s_outhist[ND_ROUTER_SOLICIT]);
+                rrddim_set_by_pointer(st, rd_in_advertisements,  icmp6stat.icp6s_inhist[ND_ROUTER_ADVERT]);
+                rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_ROUTER_ADVERT]);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_icmp6_neighbor == CONFIG_BOOLEAN_YES || (do_icmp6_neighbor == CONFIG_BOOLEAN_AUTO && (
-                                                                    icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT] ||
-                                                                    icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT] ||
-                                                                    icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT] ||
-                                                                    icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]))) {
+                    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_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmpneighbor");
-                if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmpneighbor", NULL, "icmp", NULL, "IPv6 Neighbor Messages", "messages/s", 10500, update_every, RRDSET_TYPE_LINE);
 
-                    rrddim_add(st, "InSolicits", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutSolicits", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InAdvertisements", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_solicits = NULL, *rd_out_solicits = NULL,
+                              *rd_in_advertisements = NULL, *rd_out_advertisements = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmpneighbor",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 Neighbor Messages",
+                                                 "messages/s",
+                                                 10500,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_solicits        = rrddim_add(st, "InSolicits",        NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_solicits       = rrddim_add(st, "OutSolicits",       NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_advertisements  = rrddim_add(st, "InAdvertisements",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_advertisements = rrddim_add(st, "OutAdvertisements", NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in_solicits,        icmp6stat.icp6s_inhist[ND_NEIGHBOR_SOLICIT]);
+                rrddim_set_by_pointer(st, rd_out_solicits,       icmp6stat.icp6s_outhist[ND_NEIGHBOR_SOLICIT]);
+                rrddim_set_by_pointer(st, rd_in_advertisements,  icmp6stat.icp6s_inhist[ND_NEIGHBOR_ADVERT]);
+                rrddim_set_by_pointer(st, rd_out_advertisements, icmp6stat.icp6s_outhist[ND_NEIGHBOR_ADVERT]);
                 rrdset_done(st);
             }
 
             // --------------------------------------------------------------------
 
             if (do_icmp6_types == CONFIG_BOOLEAN_YES || (do_icmp6_types == CONFIG_BOOLEAN_AUTO && (
-                                                                    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]))) {
+                    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_BOOLEAN_YES;
-                st = rrdset_find_localhost("ipv6.icmptypes");
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in_1 = NULL, *rd_in_128 = NULL, *rd_in_129 = NULL, *rd_in_136 = NULL,
+                              *rd_out_1 = NULL, *rd_out_128 = NULL, *rd_out_129 = NULL, *rd_out_133 = NULL,
+                              *rd_out_135 = NULL, *rd_out_143 = NULL;
+
                 if (unlikely(!st)) {
-                    st = rrdset_create_localhost("ipv6", "icmptypes", NULL, "icmp", NULL, "IPv6 ICMP Types",
-                                       "messages/s", 10700, update_every, RRDSET_TYPE_LINE);
-
-                    rrddim_add(st, "InType1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InType128", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InType129", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "InType136", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType1", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
-                    rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    st = rrdset_create_localhost("ipv6",
+                                                 "icmptypes",
+                                                 NULL,
+                                                 "icmp",
+                                                 NULL,
+                                                 "IPv6 ICMP Types",
+                                                 "messages/s",
+                                                 10700,
+                                                 update_every,
+                                                 RRDSET_TYPE_LINE
+                    );
+
+                    rd_in_1    = rrddim_add(st, "InType1",    NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_128  = rrddim_add(st, "InType128",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_129  = rrddim_add(st, "InType129",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_in_136  = rrddim_add(st, "InType136",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_1   = rrddim_add(st, "OutType1",   NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_128 = rrddim_add(st, "OutType128", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_129 = rrddim_add(st, "OutType129", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_133 = rrddim_add(st, "OutType133", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_135 = rrddim_add(st, "OutType135", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out_143 = rrddim_add(st, "OutType143", NULL, -1, 1, RRD_ALGORITHM_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]);
+                rrddim_set_by_pointer(st, rd_in_1,    icmp6stat.icp6s_inhist[1]);
+                rrddim_set_by_pointer(st, rd_in_128,  icmp6stat.icp6s_inhist[128]);
+                rrddim_set_by_pointer(st, rd_in_129,  icmp6stat.icp6s_inhist[129]);
+                rrddim_set_by_pointer(st, rd_in_136,  icmp6stat.icp6s_inhist[136]);
+                rrddim_set_by_pointer(st, rd_out_1,   icmp6stat.icp6s_outhist[1]);
+                rrddim_set_by_pointer(st, rd_out_128, icmp6stat.icp6s_outhist[128]);
+                rrddim_set_by_pointer(st, rd_out_129, icmp6stat.icp6s_outhist[129]);
+                rrddim_set_by_pointer(st, rd_out_133, icmp6stat.icp6s_outhist[133]);
+                rrddim_set_by_pointer(st, rd_out_135, icmp6stat.icp6s_outhist[135]);
+                rrddim_set_by_pointer(st, rd_out_143, icmp6stat.icp6s_outhist[143]);
                 rrdset_done(st);
             }
         }
+    } else {
+        error("DISABLED: net.inet6.icmp6.stats module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getmntinfo
+
+int do_getmntinfo(int update_every, usec_t dt) {
+    (void)dt;
+
+#define DELAULT_EXLUDED_PATHS "/proc/*"
+// taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
+#define DEFAULT_EXCLUDED_FILESYSTEMS "autofs procfs subfs devfs none"
+#define CONFIG_SECTION_GETMNTINFO "plugin:freebsd:getmntinfo"
+
+    static int do_space = -1, do_inodes = -1;
+
+    if (unlikely(do_space == -1)) {
+        do_space  = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "space usage for all disks",  CONFIG_BOOLEAN_AUTO);
+        do_inodes = config_get_boolean_ondemand(CONFIG_SECTION_GETMNTINFO, "inodes usage for all disks", CONFIG_BOOLEAN_AUTO);
+    }
 
     if (likely(do_space || do_inodes)) {
+        struct statfs *mntbuf;
+        int mntsize;
+
         // there is no mount info in sysctl MIBs
         if (unlikely(!(mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)))) {
             error("FREEBSD: getmntinfo() failed");
             do_space = 0;
-            error("DISABLED: disk_space.X");
+            error("DISABLED: disk_space.* charts");
             do_inodes = 0;
-            error("DISABLED: disk_inodes.X");
+            error("DISABLED: disk_inodes.* charts");
+            error("DISABLED: getmntinfo module");
+            return 1;
         } else {
+            // Data to be stored in DICTIONARY mount_points.
+            // This DICTIONARY is used to lookup the settings of the mount point on each iteration.
+            struct mount_point_metadata {
+                int do_space;
+                int do_inodes;
+
+                size_t collected; // the number of times this has been collected
+
+                // charts and dimensions
+
+                RRDSET *st_space;
+                RRDDIM *rd_space_used;
+                RRDDIM *rd_space_avail;
+                RRDDIM *rd_space_reserved;
+
+                RRDSET *st_inodes;
+                RRDDIM *rd_inodes_used;
+                RRDDIM *rd_inodes_avail;
+            };
+            static DICTIONARY *mount_points = NULL;
+            static SIMPLE_PATTERN *excluded_mountpoints = NULL;
+            static SIMPLE_PATTERN *excluded_filesystems = NULL;
+            int i;
+
+            if(unlikely(!mount_points)) {
+
+                excluded_mountpoints = simple_pattern_create(
+                        config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on paths",
+                                   DELAULT_EXLUDED_PATHS),
+                        SIMPLE_PATTERN_EXACT
+                );
+
+                excluded_filesystems = simple_pattern_create(
+                        config_get(CONFIG_SECTION_GETMNTINFO, "exclude space metrics on filesystems",
+                                   DEFAULT_EXCLUDED_FILESYSTEMS),
+                        SIMPLE_PATTERN_EXACT
+                );
+
+                mount_points = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+            }
+
             for (i = 0; i < mntsize; i++) {
-                if (mntbuf[i].f_flags == MNT_RDONLY ||
-                        mntbuf[i].f_blocks == 0 ||
-                        // taken from gnulib/mountlist.c and shortened to FreeBSD related fstypes
-                        strcmp(mntbuf[i].f_fstypename, "autofs") == 0 ||
-                        strcmp(mntbuf[i].f_fstypename, "procfs") == 0 ||
-                        strcmp(mntbuf[i].f_fstypename, "subfs") == 0 ||
-                        strcmp(mntbuf[i].f_fstypename, "devfs") == 0 ||
-                        strcmp(mntbuf[i].f_fstypename, "none") == 0)
+
+                char title[4096 + 1];
+                int def_space, def_inodes, iter_space, iter_inodes;
+
+                struct mount_point_metadata *m = dictionary_get(mount_points, mntbuf[i].f_mntonname);
+                if(unlikely(!m)) {
+                    char var_name[4096 + 1];
+                    snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETMNTINFO, mntbuf[i].f_mntonname);
+
+                    def_space = do_space;
+                    def_inodes = do_space;
+
+                    if(unlikely(simple_pattern_matches(excluded_mountpoints, mntbuf[i].f_mntonname))) {
+                        def_space = CONFIG_BOOLEAN_NO;
+                        def_inodes = CONFIG_BOOLEAN_NO;
+                    }
+
+                    if(unlikely(simple_pattern_matches(excluded_filesystems, mntbuf[i].f_fstypename))) {
+                        def_space = CONFIG_BOOLEAN_NO;
+                        def_inodes = CONFIG_BOOLEAN_NO;
+                    }
+
+                    iter_space  = config_get_boolean_ondemand(var_name, "space usage",  def_space);
+                    iter_inodes = config_get_boolean_ondemand(var_name, "inodes usage", def_inodes);
+
+                    struct mount_point_metadata mp = {
+                            .do_space = iter_space,
+                            .do_inodes = iter_inodes,
+
+                            .collected = 0,
+
+                            .st_space = NULL,
+                            .rd_space_avail = NULL,
+                            .rd_space_used = NULL,
+                            .rd_space_reserved = NULL,
+
+                            .st_inodes = NULL,
+                            .rd_inodes_avail = NULL,
+                            .rd_inodes_used = NULL,
+                    };
+
+                    m = dictionary_set(mount_points, mntbuf[i].f_mntonname, &mp, sizeof(struct mount_point_metadata));
+                }
+
+                if(unlikely(m->do_space == CONFIG_BOOLEAN_NO && m->do_inodes == CONFIG_BOOLEAN_NO))
+                    continue;
+
+                if(unlikely(mntbuf[i].f_flags & MNT_RDONLY && !m->collected))
                     continue;
 
                 // --------------------------------------------------------------------------
 
-                if (likely(do_space)) {
-                    st = rrdset_find_bytype_localhost("disk_space", mntbuf[i].f_mntonname);
-                    if (unlikely(!st)) {
-                        snprintfz(title, 4096, "Disk Space Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
-                        st = rrdset_create_localhost("disk_space", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.space", title, "GB", 2023,
-                                           update_every,
-                                           RRDSET_TYPE_STACKED);
-
-                        rrddim_add(st, "avail", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                        rrddim_add(st, "used", NULL, mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
-                        rrddim_add(st, "reserved_for_root", "reserved for root", mntbuf[i].f_bsize, GIGA_FACTOR,
-                                RRD_ALGORITHM_ABSOLUTE);
+                int rendered = 0;
+
+                if (m->do_space == CONFIG_BOOLEAN_YES || (m->do_space == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_blocks > 2))) {
+                    if (unlikely(!m->st_space)) {
+                        snprintfz(title, 4096, "Disk Space Usage for %s [%s]",
+                                  mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+                        m->st_space = rrdset_create_localhost("disk_space",
+                                                              mntbuf[i].f_mntonname,
+                                                              NULL,
+                                                              mntbuf[i].f_mntonname,
+                                                              "disk.space",
+                                                              title,
+                                                              "GB",
+                                                              2023,
+                                                              update_every,
+                                                              RRDSET_TYPE_STACKED
+                        );
+
+                        m->rd_space_avail    = rrddim_add(m->st_space, "avail", NULL,
+                                                          mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+                        m->rd_space_used     = rrddim_add(m->st_space, "used", NULL,
+                                                          mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
+                        m->rd_space_reserved = rrddim_add(m->st_space, "reserved_for_root", "reserved for root",
+                                                          mntbuf[i].f_bsize, GIGA_FACTOR, RRD_ALGORITHM_ABSOLUTE);
                     } else
-                        rrdset_next(st);
+                        rrdset_next(m->st_space);
 
-                    rrddim_set(st, "avail", (collected_number) mntbuf[i].f_bavail);
-                    rrddim_set(st, "used", (collected_number) (mntbuf[i].f_blocks - mntbuf[i].f_bfree));
-                    rrddim_set(st, "reserved_for_root", (collected_number) (mntbuf[i].f_bfree - mntbuf[i].f_bavail));
-                    rrdset_done(st);
+                    rrddim_set_by_pointer(m->st_space, m->rd_space_avail,    (collected_number) mntbuf[i].f_bavail);
+                    rrddim_set_by_pointer(m->st_space, m->rd_space_used,     (collected_number) (mntbuf[i].f_blocks -
+                                                                                                 mntbuf[i].f_bfree));
+                    rrddim_set_by_pointer(m->st_space, m->rd_space_reserved, (collected_number) (mntbuf[i].f_bfree -
+                                                                                                 mntbuf[i].f_bavail));
+                    rrdset_done(m->st_space);
+
+                    rendered++;
                 }
 
                 // --------------------------------------------------------------------------
 
-                if (likely(do_inodes)) {
-                    st = rrdset_find_bytype_localhost("disk_inodes", mntbuf[i].f_mntonname);
-                    if (unlikely(!st)) {
-                        snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]", mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
-                        st = rrdset_create_localhost("disk_inodes", mntbuf[i].f_mntonname, NULL, mntbuf[i].f_mntonname, "disk.inodes", title, "Inodes", 2024,
-                                           update_every, RRDSET_TYPE_STACKED);
-
-                        rrddim_add(st, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                        rrddim_add(st, "used", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
-                        rrddim_add(st, "reserved_for_root", "reserved for root", 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                if (m->do_inodes == CONFIG_BOOLEAN_YES || (m->do_inodes == CONFIG_BOOLEAN_AUTO && (mntbuf[i].f_files > 1))) {
+                    if (unlikely(!m->st_inodes)) {
+                        snprintfz(title, 4096, "Disk Files (inodes) Usage for %s [%s]",
+                                  mntbuf[i].f_mntonname, mntbuf[i].f_mntfromname);
+                        m->st_inodes = rrdset_create_localhost("disk_inodes",
+                                                               mntbuf[i].f_mntonname,
+                                                               NULL,
+                                                               mntbuf[i].f_mntonname,
+                                                               "disk.inodes",
+                                                               title,
+                                                               "Inodes",
+                                                               2024,
+                                                               update_every,
+                                                               RRDSET_TYPE_STACKED
+                        );
+
+                        m->rd_inodes_avail = rrddim_add(m->st_inodes, "avail", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                        m->rd_inodes_used  = rrddim_add(m->st_inodes, "used",  NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
                     } else
-                        rrdset_next(st);
+                        rrdset_next(m->st_inodes);
 
-                    rrddim_set(st, "avail", (collected_number) mntbuf[i].f_ffree);
-                    rrddim_set(st, "used", (collected_number) (mntbuf[i].f_files - mntbuf[i].f_ffree));
-                    rrdset_done(st);
+                    rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_avail, (collected_number) mntbuf[i].f_ffree);
+                    rrddim_set_by_pointer(m->st_inodes, m->rd_inodes_used,  (collected_number) (mntbuf[i].f_files -
+                                                                                                mntbuf[i].f_ffree));
+                    rrdset_done(m->st_inodes);
+
+                    rendered++;
                 }
+
+                if(likely(rendered))
+                    m->collected++;
             }
         }
+    } else {
+        error("DISABLED: getmntinfo module");
+        return 1;
     }
 
-    // --------------------------------------------------------------------
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// getifaddrs
+
+int do_getifaddrs(int update_every, usec_t dt) {
+    (void)dt;
+
+#define DELAULT_EXLUDED_INTERFACES "lo*"
+#define CONFIG_SECTION_GETIFADDRS "plugin:freebsd:getifaddrs"
+
+    static int do_bandwidth_ipv4 = -1, do_bandwidth_ipv6 = -1, do_bandwidth = -1, do_packets = -1,
+               do_errors = -1, do_drops = -1, do_events = -1;
+
+    if (unlikely(do_bandwidth_ipv4 == -1)) {
+        do_bandwidth_ipv4 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv4 interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_bandwidth_ipv6 = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "total bandwidth for ipv6 interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_bandwidth      = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "bandwidth for all interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_packets        = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "packets for all interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_errors         = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "errors for all interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_drops          = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "drops for all interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+        do_events         = config_get_boolean_ondemand(CONFIG_SECTION_GETIFADDRS, "collisions for all interfaces",
+                                                        CONFIG_BOOLEAN_AUTO);
+    }
 
-    if (likely(do_uptime)) {
-            clock_gettime(CLOCK_UPTIME, &up_time);
-            st = rrdset_find_localhost("system.uptime");
+    if (likely(do_bandwidth_ipv4 || do_bandwidth_ipv6 || do_bandwidth || do_packets || do_errors ||
+               do_drops || do_events)) {
+        struct ifaddrs *ifap;
 
-            if(unlikely(!st)) {
-                st = rrdset_create_localhost("system", "uptime", NULL, "uptime", NULL, "System Uptime", "seconds", 1000, update_every, RRDSET_TYPE_LINE);
-                rrddim_add(st, "uptime", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+        if (unlikely(getifaddrs(&ifap))) {
+            error("FREEBSD: getifaddrs() failed");
+            do_bandwidth_ipv4 = 0;
+            error("DISABLED: system.ipv4 chart");
+            do_bandwidth_ipv6 = 0;
+            error("DISABLED: system.ipv6 chart");
+            do_bandwidth = 0;
+            error("DISABLED: net.* charts");
+            do_packets = 0;
+            error("DISABLED: net_packets.* charts");
+            do_errors = 0;
+            error("DISABLED: net_errors.* charts");
+            do_drops = 0;
+            error("DISABLED: net_drops.* charts");
+            do_events = 0;
+            error("DISABLED: net_events.* charts");
+            error("DISABLED: getifaddrs module");
+            return 1;
+        } else {
+            #define IFA_DATA(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s)
+            struct ifaddrs *ifa;
+            struct iftot {
+                u_long  ift_ibytes;
+                u_long  ift_obytes;
+            } iftot = {0, 0};
+
+            // --------------------------------------------------------------------
+
+            if (likely(do_bandwidth_ipv4)) {
+                iftot.ift_ibytes = iftot.ift_obytes = 0;
+                for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                    if (ifa->ifa_addr->sa_family != AF_INET)
+                        continue;
+                    iftot.ift_ibytes += IFA_DATA(ibytes);
+                    iftot.ift_obytes += IFA_DATA(obytes);
+                }
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("system",
+                                                 "ipv4",
+                                                 NULL,
+                                                 "network",
+                                                 NULL,
+                                                 "IPv4 Bandwidth",
+                                                 "kilobits/s",
+                                                 500,
+                                                 update_every,
+                                                 RRDSET_TYPE_AREA
+                    );
+
+                    rd_in  = rrddim_add(st, "InOctets",  "received", 8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out = rrddim_add(st, "OutOctets", "sent",    -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set_by_pointer(st, rd_in,  iftot.ift_ibytes);
+                rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+                rrdset_done(st);
             }
-            else rrdset_next(st);
 
-            rrddim_set(st, "uptime", up_time.tv_sec);
-            rrdset_done(st);
+            // --------------------------------------------------------------------
+
+            if (likely(do_bandwidth_ipv6)) {
+                iftot.ift_ibytes = iftot.ift_obytes = 0;
+                for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                    if (ifa->ifa_addr->sa_family != AF_INET6)
+                        continue;
+                    iftot.ift_ibytes += IFA_DATA(ibytes);
+                    iftot.ift_obytes += IFA_DATA(obytes);
+                }
+
+                static RRDSET *st = NULL;
+                static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+                if (unlikely(!st)) {
+                    st = rrdset_create_localhost("system",
+                                                 "ipv6",
+                                                 NULL,
+                                                 "network",
+                                                 NULL,
+                                                 "IPv6 Bandwidth",
+                                                 "kilobits/s",
+                                                 500,
+                                                 update_every,
+                                                 RRDSET_TYPE_AREA
+                    );
+
+                    rd_in  = rrddim_add(st, "received", NULL,  8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+                    rd_out = rrddim_add(st, "sent",     NULL, -8, KILO_FACTOR, RRD_ALGORITHM_INCREMENTAL);
+                } else
+                    rrdset_next(st);
+
+                rrddim_set_by_pointer(st, rd_in,  iftot.ift_ibytes);
+                rrddim_set_by_pointer(st, rd_out, iftot.ift_obytes);
+                rrdset_done(st);
+            }
+
+            // --------------------------------------------------------------------
+
+            // Data to be stored in DICTIONARY interfaces.
+            // This DICTIONARY is used to lookup the settings of the interfaces on each iteration.
+            struct interfaces_metadata {
+                int do_bandwidth;
+                int do_packets;
+                int do_errors;
+                int do_drops;
+                int do_events;
+
+                // charts and dimensions
+
+                RRDSET *st_bandwidth;
+                RRDDIM *rd_bandwidth_in;
+                RRDDIM *rd_bandwidth_out;
+
+                RRDSET *st_packets;
+                RRDDIM *rd_packets_in;
+                RRDDIM *rd_packets_out;
+                RRDDIM *rd_packets_m_in;
+                RRDDIM *rd_packets_m_out;
+
+                RRDSET *st_errors;
+                RRDDIM *rd_errors_in;
+                RRDDIM *rd_errors_out;
+
+                RRDSET *st_drops;
+                RRDDIM *rd_drops_in;
+                RRDDIM *rd_drops_out;
+
+                RRDSET *st_events;
+                RRDDIM *rd_events_coll;
+            };
+            static DICTIONARY *interfaces = NULL;
+            static SIMPLE_PATTERN *excluded_interfaces = NULL;
+
+            if(unlikely(!interfaces)) {
+
+                excluded_interfaces = simple_pattern_create(
+                        config_get(CONFIG_SECTION_GETIFADDRS, "disable by default interfaces matching",
+                                   DELAULT_EXLUDED_INTERFACES)
+                        , SIMPLE_PATTERN_EXACT
+                );
+
+                interfaces = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+            }
+
+            for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
+                if (ifa->ifa_addr->sa_family != AF_LINK)
+                    continue;
+
+                int def_bandwidth, def_packets, def_errors, def_drops, def_events,
+                    iter_bandwidth, iter_packets, iter_errors, iter_drops, iter_events;
+
+                struct interfaces_metadata *ifm = dictionary_get(interfaces, ifa->ifa_name);
+                if(unlikely(!ifm)) {
+                    char var_name[4096 + 1];
+                    snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_GETIFADDRS, ifa->ifa_name);
+
+                    def_bandwidth = do_bandwidth;
+                    def_packets   = do_packets;
+                    def_errors    = do_errors;
+                    def_drops     = do_drops;
+                    def_events    = do_events;
+
+                    if(unlikely(simple_pattern_matches(excluded_interfaces, ifa->ifa_name))) {
+                        def_bandwidth = CONFIG_BOOLEAN_NO;
+                        def_packets   = CONFIG_BOOLEAN_NO;
+                        def_errors    = CONFIG_BOOLEAN_NO;
+                        def_drops     = CONFIG_BOOLEAN_NO;
+                        def_events    = CONFIG_BOOLEAN_NO;
+                    }
+
+                    iter_bandwidth = config_get_boolean_ondemand(var_name, "bandwidth", def_bandwidth);
+                    iter_packets   = config_get_boolean_ondemand(var_name, "packets",   def_packets);
+                    iter_errors    = config_get_boolean_ondemand(var_name, "errors",    def_errors);
+                    iter_drops     = config_get_boolean_ondemand(var_name, "drops",     def_drops);
+                    iter_events    = config_get_boolean_ondemand(var_name, "events",    def_events);
+
+                    struct interfaces_metadata ifmp = {
+                            .do_bandwidth = iter_bandwidth,
+                            .do_packets   = iter_packets,
+                            .do_errors    = iter_errors,
+                            .do_drops     = iter_drops,
+                            .do_events    = iter_events,
+
+                            .st_bandwidth = NULL,
+                            .rd_bandwidth_in = NULL,
+                            .rd_bandwidth_out = NULL,
+
+                            .st_packets = NULL,
+                            .rd_packets_in = NULL,
+                            .rd_packets_out = NULL,
+                            .rd_packets_m_in = NULL,
+                            .rd_packets_m_out = NULL,
+
+                            .st_errors = NULL,
+                            .rd_errors_in = NULL,
+                            .rd_errors_out = NULL,
+
+                            .st_drops = NULL,
+                            .rd_drops_in = NULL,
+                            .rd_drops_out = NULL,
+
+                            .st_events = NULL,
+                            .rd_events_coll = NULL,
+                    };
+
+                    ifm = dictionary_set(interfaces, ifa->ifa_name, &ifmp, sizeof(struct interfaces_metadata));
+                }
+
+                // --------------------------------------------------------------------
+
+                if (ifm->do_bandwidth == CONFIG_BOOLEAN_YES || (ifm->do_bandwidth == CONFIG_BOOLEAN_AUTO &&
+                        (IFA_DATA(ibytes) || IFA_DATA(obytes)))) {
+                    if (unlikely(!ifm->st_bandwidth)) {
+                        ifm->st_bandwidth = rrdset_create_localhost("net",
+                                                                    ifa->ifa_name,
+                                                                    NULL,
+                                                                    ifa->ifa_name,
+                                                                    "net.net",
+                                                                    "Bandwidth",
+                                                                    "kilobits/s",
+                                                                    7000,
+                                                                    update_every,
+                                                                    RRDSET_TYPE_AREA
+                        );
+
+                        ifm->rd_bandwidth_in  = rrddim_add(ifm->st_bandwidth, "received", NULL,  8, KILO_FACTOR,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                        ifm->rd_bandwidth_out = rrddim_add(ifm->st_bandwidth, "sent",     NULL, -8, KILO_FACTOR,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                    } else
+                        rrdset_next(ifm->st_bandwidth);
+
+                    rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_in,  IFA_DATA(ibytes));
+                    rrddim_set_by_pointer(ifm->st_bandwidth, ifm->rd_bandwidth_out, IFA_DATA(obytes));
+                    rrdset_done(ifm->st_bandwidth);
+                }
+
+                // --------------------------------------------------------------------
+
+                if (ifm->do_packets == CONFIG_BOOLEAN_YES || (ifm->do_packets == CONFIG_BOOLEAN_AUTO &&
+                        (IFA_DATA(ipackets) || IFA_DATA(opackets) || IFA_DATA(imcasts) || IFA_DATA(omcasts)))) {
+                    if (unlikely(!ifm->st_packets)) {
+                        ifm->st_packets = rrdset_create_localhost("net_packets",
+                                                                  ifa->ifa_name,
+                                                                  NULL,
+                                                                  ifa->ifa_name,
+                                                                  "net.packets",
+                                                                  "Packets",
+                                                                  "packets/s",
+                                                                  7001,
+                                                                  update_every,
+                                                                  RRDSET_TYPE_LINE
+                        );
+
+                        rrdset_flag_set(ifm->st_packets, RRDSET_FLAG_DETAIL);
+
+                        ifm->rd_packets_in    = rrddim_add(ifm->st_packets, "received",           NULL,  1, 1,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                        ifm->rd_packets_out   = rrddim_add(ifm->st_packets, "sent",               NULL, -1, 1,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                        ifm->rd_packets_m_in  = rrddim_add(ifm->st_packets, "multicast_received", NULL,  1, 1,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                        ifm->rd_packets_m_out = rrddim_add(ifm->st_packets, "multicast_sent",     NULL, -1, 1,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                    } else
+                        rrdset_next(ifm->st_packets);
+
+                    rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_in,    IFA_DATA(ipackets));
+                    rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_out,   IFA_DATA(opackets));
+                    rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_in,  IFA_DATA(imcasts));
+                    rrddim_set_by_pointer(ifm->st_packets, ifm->rd_packets_m_out, IFA_DATA(omcasts));
+                    rrdset_done(ifm->st_packets);
+                }
+
+                // --------------------------------------------------------------------
+
+                if (ifm->do_errors == CONFIG_BOOLEAN_YES || (ifm->do_errors == CONFIG_BOOLEAN_AUTO &&
+                        (IFA_DATA(ierrors) || IFA_DATA(oerrors)))) {
+                    if (unlikely(!ifm->st_errors)) {
+                        ifm->st_errors = rrdset_create_localhost("net_errors",
+                                                                 ifa->ifa_name,
+                                                                 NULL,
+                                                                 ifa->ifa_name,
+                                                                 "net.errors",
+                                                                 "Interface Errors",
+                                                                 "errors/s",
+                                                                 7002,
+                                                                 update_every,
+                                                                 RRDSET_TYPE_LINE
+                        );
+
+                        rrdset_flag_set(ifm->st_errors, RRDSET_FLAG_DETAIL);
+
+                        ifm->rd_errors_in  = rrddim_add(ifm->st_errors, "inbound",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                        ifm->rd_errors_out = rrddim_add(ifm->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    } else
+                        rrdset_next(ifm->st_errors);
+
+                    rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_in,  IFA_DATA(ierrors));
+                    rrddim_set_by_pointer(ifm->st_errors, ifm->rd_errors_out, IFA_DATA(oerrors));
+                    rrdset_done(ifm->st_errors);
+                }
+                // --------------------------------------------------------------------
+
+                if (ifm->do_drops == CONFIG_BOOLEAN_YES || (ifm->do_drops == CONFIG_BOOLEAN_AUTO &&
+                        (IFA_DATA(iqdrops) || IFA_DATA(oqdrops)))) {
+                    if (unlikely(!ifm->st_drops)) {
+                        ifm->st_drops = rrdset_create_localhost("net_drops",
+                                                                ifa->ifa_name,
+                                                                NULL,
+                                                                ifa->ifa_name,
+                                                                "net.drops",
+                                                                "Interface Drops",
+                                                                "drops/s",
+                                                                7003,
+                                                                update_every,
+                                                                RRDSET_TYPE_LINE
+                        );
+
+                        rrdset_flag_set(ifm->st_drops, RRDSET_FLAG_DETAIL);
+
+                        ifm->rd_drops_in  = rrddim_add(ifm->st_drops, "inbound",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+#if __FreeBSD__ >= 11
+                        ifm->rd_drops_out = rrddim_add(ifm->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+#endif
+                    } else
+                        rrdset_next(ifm->st_drops);
+
+                    rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_in,  IFA_DATA(iqdrops));
+#if __FreeBSD__ >= 11
+                    rrddim_set_by_pointer(ifm->st_drops, ifm->rd_drops_out, IFA_DATA(oqdrops));
+#endif
+                    rrdset_done(ifm->st_drops);
+                }
+
+                // --------------------------------------------------------------------
+
+                if (ifm->do_events == CONFIG_BOOLEAN_YES || (ifm->do_events == CONFIG_BOOLEAN_AUTO &&
+                                                             IFA_DATA(collisions))) {
+                    if (unlikely(!ifm->st_events)) {
+                        ifm->st_events = rrdset_create_localhost("net_events",
+                                                                 ifa->ifa_name,
+                                                                 NULL,
+                                                                 ifa->ifa_name,
+                                                                 "net.events",
+                                                                 "Network Interface Events",
+                                                                 "events/s",
+                                                                 7006,
+                                                                 update_every,
+                                                                 RRDSET_TYPE_LINE
+                        );
+
+                        rrdset_flag_set(ifm->st_events, RRDSET_FLAG_DETAIL);
+
+                        ifm->rd_events_coll = rrddim_add(ifm->st_events, "collisions", NULL, -1, 1,
+                                                         RRD_ALGORITHM_INCREMENTAL);
+                    } else
+                        rrdset_next(ifm->st_events);
+
+                    rrddim_set_by_pointer(ifm->st_events, ifm->rd_events_coll, IFA_DATA(collisions));
+                    rrdset_done(ifm->st_events);
+                }
+            }
+
+            freeifaddrs(ifap);
+        }
+    } else {
+        error("DISABLED: getifaddrs module");
+        return 1;
+    }
+
+    return 0;
+}
+
+// --------------------------------------------------------------------------------------------------------------------
+// kern.devstat
+
+int do_kern_devstat(int update_every, usec_t dt) {
+
+#define DELAULT_EXLUDED_DISKS ""
+#define CONFIG_SECTION_KERN_DEVSTAT "plugin:freebsd:kern.devstat"
+#define BINTIME_SCALE 5.42101086242752217003726400434970855712890625e-17 // this is 1000/2^64
+
+    static int enable_pass_devices = -1, do_system_io = -1, do_io = -1, do_ops = -1, do_qops = -1, do_util = -1,
+               do_iotime = -1, do_await = -1, do_avagsz = -1, do_svctm = -1;
+
+    if (unlikely(enable_pass_devices == -1)) {
+        enable_pass_devices = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT,
+                                                          "performance metrics for pass devices", CONFIG_BOOLEAN_AUTO);
+
+        do_system_io = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "total bandwidth for all disks",
+                                                   CONFIG_BOOLEAN_YES);
+
+        do_io     = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "bandwidth for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_ops    = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "operations for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_qops   = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "queued operations for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_util   = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "utilization percentage for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_iotime = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "i/o time for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_await  = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o time for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_avagsz = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average completed i/o bandwidth for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+        do_svctm  = config_get_boolean_ondemand(CONFIG_SECTION_KERN_DEVSTAT, "average service time for all disks",
+                                                CONFIG_BOOLEAN_AUTO);
+    }
+
+    if (likely(do_system_io || do_io || do_ops || do_qops || do_util || do_iotime || do_await || do_avagsz || do_svctm)) {
+        static int mib_numdevs[3] = {0, 0, 0};
+        int numdevs;
+        int common_error = 0;
+
+        if (unlikely(GETSYSCTL_SIMPLE("kern.devstat.numdevs", mib_numdevs, numdevs))) {
+            common_error = 1;
+        } else {
+            static int mib_devstat[3] = {0, 0, 0};
+            static void *devstat_data = NULL;
+
+            devstat_data = reallocz(devstat_data, sizeof(long) + sizeof(struct devstat) * numdevs); // there is generation number before devstat structures
+            if (unlikely(GETSYSCTL_WSIZE("kern.devstat.all", mib_devstat, devstat_data,
+                                         sizeof(long) + sizeof(struct devstat) * numdevs))) {
+                common_error = 1;
+            } else {
+                struct devstat *dstat;
+                int i;
+                collected_number total_disk_kbytes_read = 0;
+                collected_number total_disk_kbytes_write = 0;
+
+                // Data to be stored in DICTIONARY disks.
+                // This DICTIONARY is used to lookup the settings of the disks on each iteration.
+                struct disks_metadata {
+                    int do_io;
+                    int do_ops;
+                    int do_qops;
+                    int do_util;
+                    int do_iotime;
+                    int do_await;
+                    int do_avagsz;
+                    int do_svctm;
+
+
+                    // data for differential charts
+
+                    struct prev_dstat {
+                        collected_number bytes_read;
+                        collected_number bytes_write;
+                        collected_number operations_read;
+                        collected_number operations_write;
+                        collected_number duration_read_ms;
+                        collected_number duration_write_ms;
+                        collected_number busy_time_ms;
+                    } prev_dstat;
+
+                    // charts and dimensions
+
+                    RRDSET *st_io;
+                    RRDDIM *rd_io_in;
+                    RRDDIM *rd_io_out;
+
+                    RRDSET *st_ops;
+                    RRDDIM *rd_ops_in;
+                    RRDDIM *rd_ops_out;
+
+                    RRDSET *st_qops;
+                    RRDDIM *rd_qops;
+
+                    RRDSET *st_util;
+                    RRDDIM *rd_util;
+
+                    RRDSET *st_iotime;
+                    RRDDIM *rd_iotime_in;
+                    RRDDIM *rd_iotime_out;
+
+                    RRDSET *st_await;
+                    RRDDIM *rd_await_in;
+                    RRDDIM *rd_await_out;
+
+                    RRDSET *st_avagsz;
+                    RRDDIM *rd_avagsz_in;
+                    RRDDIM *rd_avagsz_out;
+
+                    RRDSET *st_svctm;
+                    RRDDIM *rd_svctm;
+
+                };
+                static DICTIONARY *disks = NULL;
+                static SIMPLE_PATTERN *excluded_disks = NULL;
+
+                if(unlikely(!disks)) {
+
+                    excluded_disks = simple_pattern_create(
+                            config_get(CONFIG_SECTION_KERN_DEVSTAT, "disable by default disks matching",
+                                       DELAULT_EXLUDED_DISKS)
+                            , SIMPLE_PATTERN_EXACT
+                    );
+
+                    disks = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
+                }
+
+                dstat = devstat_data + sizeof(long); // skip generation number
+
+                for (i = 0; i < numdevs; i++) {
+                    if (likely(do_system_io)) {
+                        if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+                            total_disk_kbytes_read += dstat[i].bytes[DEVSTAT_READ] / KILO_FACTOR;
+                            total_disk_kbytes_write += dstat[i].bytes[DEVSTAT_WRITE] / KILO_FACTOR;
+                        }
+                    }
+
+                    if (unlikely(!enable_pass_devices))
+                        if ((dstat[i].device_type & DEVSTAT_TYPE_PASS) == DEVSTAT_TYPE_PASS)
+                            continue;
+
+                    if (((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_DIRECT) || ((dstat[i].device_type & DEVSTAT_TYPE_MASK) == DEVSTAT_TYPE_STORARRAY)) {
+                        char disk[DEVSTAT_NAME_LEN + MAX_INT_DIGITS + 1];
+                        int def_io, def_ops, def_qops, def_util, def_iotime, def_await, def_avagsz, def_svctm,
+                            iter_io, iter_ops, iter_qops, iter_util, iter_iotime, iter_await, iter_avagsz, iter_svctm;
+                        struct cur_dstat {
+                            collected_number duration_read_ms;
+                            collected_number duration_write_ms;
+                            collected_number busy_time_ms;
+                        } cur_dstat;
+
+                        sprintf(disk, "%s%d", dstat[i].device_name, dstat[i].unit_number);
+
+                        struct disks_metadata *dm = dictionary_get(disks, disk);
+                        if(unlikely(!dm)) {
+                            char var_name[4096 + 1];
+                            snprintfz(var_name, 4096, "%s:%s", CONFIG_SECTION_KERN_DEVSTAT, disk);
+
+                            def_io     = do_io;
+                            def_ops    = do_ops;
+                            def_qops   = do_qops;
+                            def_util   = do_util;
+                            def_iotime = do_iotime;
+                            def_await  = do_await;
+                            def_avagsz = do_avagsz;
+                            def_svctm  = do_svctm;
+
+                            if(unlikely(simple_pattern_matches(excluded_disks, disk))) {
+                                def_io     = CONFIG_BOOLEAN_NO;
+                                def_ops    = CONFIG_BOOLEAN_NO;
+                                def_qops   = CONFIG_BOOLEAN_NO;
+                                def_util   = CONFIG_BOOLEAN_NO;
+                                def_iotime = CONFIG_BOOLEAN_NO;
+                                def_await  = CONFIG_BOOLEAN_NO;
+                                def_avagsz = CONFIG_BOOLEAN_NO;
+                                def_svctm  = CONFIG_BOOLEAN_NO;
+                            }
+
+                            iter_io     = config_get_boolean_ondemand(var_name, "bandwidth",                  def_io);
+                            iter_ops    = config_get_boolean_ondemand(var_name, "operations",                 def_ops);
+                            iter_qops   = config_get_boolean_ondemand(var_name, "queued operations",          def_qops);
+                            iter_util   = config_get_boolean_ondemand(var_name, "utilization percentage",     def_util);
+                            iter_iotime = config_get_boolean_ondemand(var_name, "i/o time",                   def_iotime);
+                            iter_await  = config_get_boolean_ondemand(var_name, "average completed i/o time", def_await);
+                            iter_avagsz = config_get_boolean_ondemand(var_name, "average completed i/o bandwidth",
+                                                                                                              def_avagsz);
+                            iter_svctm  = config_get_boolean_ondemand(var_name, "average service time",       def_svctm);
+
+                            struct disks_metadata dmp = {
+                                    .do_io     = iter_io,
+                                    .do_ops    = iter_ops,
+                                    .do_qops   = iter_qops,
+                                    .do_util   = iter_util,
+                                    .do_iotime = iter_iotime,
+                                    .do_await  = iter_await,
+                                    .do_avagsz = iter_avagsz,
+                                    .do_svctm  = iter_svctm,
+
+                                    .st_io = NULL,
+                                    .rd_io_in = NULL,
+                                    .rd_io_out = NULL,
+
+                                    .st_ops = NULL,
+                                    .rd_ops_in = NULL,
+                                    .rd_ops_out = NULL,
+
+                                    .st_qops = NULL,
+                                    .rd_qops = NULL,
+
+                                    .st_util = NULL,
+                                    .rd_util = NULL,
+
+                                    .st_iotime = NULL,
+                                    .rd_iotime_in = NULL,
+                                    .rd_iotime_out = NULL,
+
+                                    .st_await = NULL,
+                                    .rd_await_in = NULL,
+                                    .rd_await_out = NULL,
+
+                                    .st_avagsz = NULL,
+                                    .rd_avagsz_in = NULL,
+                                    .rd_avagsz_out = NULL,
+
+                                    .st_svctm = NULL,
+                                    .rd_svctm = NULL,
+                            };
+
+                            // initialise data for differential charts
+
+                            dmp.prev_dstat.bytes_read        = dstat[i].bytes[DEVSTAT_READ];
+                            dmp.prev_dstat.bytes_write       = dstat[i].bytes[DEVSTAT_WRITE];
+                            dmp.prev_dstat.operations_read   = dstat[i].operations[DEVSTAT_READ];
+                            dmp.prev_dstat.operations_write  = dstat[i].operations[DEVSTAT_WRITE];
+                            dmp.prev_dstat.duration_read_ms  = dstat[i].duration[DEVSTAT_READ].sec * 1000
+                                                               + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+                            dmp.prev_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+                                                               + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+                            dmp.prev_dstat.busy_time_ms      = dstat[i].busy_time.sec * 1000
+                                                               + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+                            dm = dictionary_set(disks, disk, &dmp, sizeof(struct disks_metadata));
+                        }
+
+                        cur_dstat.duration_read_ms  = dstat[i].duration[DEVSTAT_READ].sec * 1000
+                                                      + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+                        cur_dstat.duration_write_ms = dstat[i].duration[DEVSTAT_WRITE].sec * 1000
+                                                      + dstat[i].duration[DEVSTAT_READ].frac * BINTIME_SCALE;
+                        cur_dstat.busy_time_ms = dstat[i].busy_time.sec * 1000 + dstat[i].busy_time.frac * BINTIME_SCALE;
+
+                        // --------------------------------------------------------------------
+
+                        if(dm->do_io == CONFIG_BOOLEAN_YES || (dm->do_io == CONFIG_BOOLEAN_AUTO &&
+                                (dstat[i].bytes[DEVSTAT_READ] || dstat[i].bytes[DEVSTAT_WRITE]))) {
+                            if (unlikely(!dm->st_io)) {
+                                dm->st_io = rrdset_create_localhost("disk",
+                                                                    disk,
+                                                                    NULL,
+                                                                    disk,
+                                                                    "disk.io",
+                                                                    "Disk I/O Bandwidth",
+                                                                    "kilobytes/s",
+                                                                    2000,
+                                                                    update_every,
+                                                                    RRDSET_TYPE_AREA
+                                );
+
+                                dm->rd_io_in  = rrddim_add(dm->st_io, "reads",  NULL,  1, KILO_FACTOR,
+                                                          RRD_ALGORITHM_INCREMENTAL);
+                                dm->rd_io_out = rrddim_add(dm->st_io, "writes", NULL, -1, KILO_FACTOR,
+                                                           RRD_ALGORITHM_INCREMENTAL);
+                            } else
+                                rrdset_next(dm->st_io);
+
+                            rrddim_set_by_pointer(dm->st_io, dm->rd_io_in,  dstat[i].bytes[DEVSTAT_READ]);
+                            rrddim_set_by_pointer(dm->st_io, dm->rd_io_out, dstat[i].bytes[DEVSTAT_WRITE]);
+                            rrdset_done(dm->st_io);
+                        }
+
+                        // --------------------------------------------------------------------
+
+                        if(dm->do_ops == CONFIG_BOOLEAN_YES || (dm->do_ops == CONFIG_BOOLEAN_AUTO &&
+                                (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+                            if (unlikely(!dm->st_ops)) {
+                                dm->st_ops = rrdset_create_localhost("disk_ops",
+                                                                     disk,
+                                                                     NULL,
+                                                                     disk,
+                                                                     "disk.ops",
+                                                                     "Disk Completed I/O Operations",
+                                                                     "operations/s",
+                                                                     2001,
+                                                                     update_every,
+                                                                     RRDSET_TYPE_LINE
+                                );
+
+                                rrdset_flag_set(dm->st_ops, RRDSET_FLAG_DETAIL);
+
+                                dm->rd_ops_in = rrddim_add(dm->st_ops, "reads", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+                                dm->rd_ops_out = rrddim_add(dm->st_ops, "writes", NULL, -1, 1,
+                                                            RRD_ALGORITHM_INCREMENTAL);
+                            } else
+                                rrdset_next(dm->st_ops);
+
+                            rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_in, dstat[i].operations[DEVSTAT_READ]);
+                            rrddim_set_by_pointer(dm->st_ops, dm->rd_ops_out, dstat[i].operations[DEVSTAT_WRITE]);
+                            rrdset_done(dm->st_ops);
+                        }
+
+                        // --------------------------------------------------------------------
+
+                        if(dm->do_qops == CONFIG_BOOLEAN_YES || (dm->do_qops == CONFIG_BOOLEAN_AUTO &&
+                                (dstat[i].start_count || dstat[i].end_count))) {
+                            if (unlikely(!dm->st_qops)) {
+                                dm->st_qops = rrdset_create_localhost("disk_qops",
+                                                                      disk,
+                                                                      NULL,
+                                                                      disk,
+                                                                      "disk.qops",
+                                                                      "Disk Current I/O Operations",
+                                                                      "operations",
+                                                                      2002,
+                                                                      update_every,
+                                                                      RRDSET_TYPE_LINE
+                                );
+
+                                rrdset_flag_set(dm->st_qops, RRDSET_FLAG_DETAIL);
+
+                                dm->rd_qops = rrddim_add(dm->st_qops, "operations", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
+                            } else
+                                rrdset_next(dm->st_qops);
+
+                            rrddim_set_by_pointer(dm->st_qops, dm->rd_qops, dstat[i].start_count - dstat[i].end_count);
+                            rrdset_done(dm->st_qops);
+                        }
+
+                        // --------------------------------------------------------------------
+
+                        if(dm->do_util == CONFIG_BOOLEAN_YES || (dm->do_util == CONFIG_BOOLEAN_AUTO &&
+                                                                 cur_dstat.busy_time_ms)) {
+                            if (unlikely(!dm->st_util)) {
+                                dm->st_util = rrdset_create_localhost("disk_util",
+                                                                      disk,
+                                                                      NULL,
+                                                                      disk,
+                                                                      "disk.util",
+                                                                      "Disk Utilization Time",
+                                                                      "% of time working",
+                                                                      2004,
+                                                                      update_every,
+                                                                      RRDSET_TYPE_AREA
+                                );
+
+                                rrdset_flag_set(dm->st_util, RRDSET_FLAG_DETAIL);
+
+                                dm->rd_util = rrddim_add(dm->st_util, "utilization", NULL, 1, 10,
+                                                         RRD_ALGORITHM_INCREMENTAL);
+                            } else
+                                rrdset_next(dm->st_util);
+
+                            rrddim_set_by_pointer(dm->st_util, dm->rd_util, cur_dstat.busy_time_ms);
+                            rrdset_done(dm->st_util);
+                        }
+
+                        // --------------------------------------------------------------------
+
+                        if(dm->do_iotime == CONFIG_BOOLEAN_YES || (dm->do_iotime == CONFIG_BOOLEAN_AUTO &&
+                                (cur_dstat.duration_read_ms || cur_dstat.duration_write_ms))) {
+                            if (unlikely(!dm->st_iotime)) {
+                                dm->st_iotime = rrdset_create_localhost("disk_iotime",
+                                                                        disk,
+                                                                        NULL,
+                                                                        disk,
+                                                                        "disk.iotime",
+                                                                        "Disk Total I/O Time",
+                                                                        "milliseconds/s",
+                                                                        2022,
+                                                                        update_every,
+                                                                        RRDSET_TYPE_LINE
+                                );
+
+                                rrdset_flag_set(dm->st_iotime, RRDSET_FLAG_DETAIL);
+
+                                dm->rd_iotime_in  = rrddim_add(dm->st_iotime, "reads",  NULL,  1, 1,
+                                                               RRD_ALGORITHM_INCREMENTAL);
+                                dm->rd_iotime_out = rrddim_add(dm->st_iotime, "writes", NULL, -1, 1,
+                                                               RRD_ALGORITHM_INCREMENTAL);
+                            } else
+                                rrdset_next(dm->st_iotime);
+
+                            rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_in,  cur_dstat.duration_read_ms);
+                            rrddim_set_by_pointer(dm->st_iotime, dm->rd_iotime_out, cur_dstat.duration_write_ms);
+                            rrdset_done(dm->st_iotime);
+                        }
+
+                        // --------------------------------------------------------------------
+                        // calculate differential charts
+                        // only if this is not the first time we run
+
+                        if (likely(dt)) {
+
+                            // --------------------------------------------------------------------
+
+                            if(dm->do_await == CONFIG_BOOLEAN_YES || (dm->do_await == CONFIG_BOOLEAN_AUTO &&
+                                    (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+                                if (unlikely(!dm->st_await)) {
+                                    dm->st_await = rrdset_create_localhost("disk_await",
+                                                                           disk,
+                                                                           NULL,
+                                                                           disk,
+                                                                           "disk.await",
+                                                                           "Average Completed I/O Operation Time",
+                                                                           "ms per operation",
+                                                                           2005,
+                                                                           update_every,
+                                                                           RRDSET_TYPE_LINE
+                                    );
+
+                                    rrdset_flag_set(dm->st_await, RRDSET_FLAG_DETAIL);
+
+                                    dm->rd_await_in  = rrddim_add(dm->st_await, "reads",  NULL,  1, 1,
+                                                                  RRD_ALGORITHM_ABSOLUTE);
+                                    dm->rd_await_out = rrddim_add(dm->st_await, "writes", NULL, -1, 1,
+                                                                  RRD_ALGORITHM_ABSOLUTE);
+                                } else
+                                    rrdset_next(dm->st_await);
+
+                                rrddim_set_by_pointer(dm->st_await, dm->rd_await_in,
+                                                      (dstat[i].operations[DEVSTAT_READ] -
+                                                       dm->prev_dstat.operations_read) ?
+                                                      (cur_dstat.duration_read_ms - dm->prev_dstat.duration_read_ms) /
+                                                      (dstat[i].operations[DEVSTAT_READ] -
+                                                       dm->prev_dstat.operations_read) :
+                                                      0);
+                                rrddim_set_by_pointer(dm->st_await, dm->rd_await_out,
+                                                      (dstat[i].operations[DEVSTAT_WRITE] -
+                                                       dm->prev_dstat.operations_write) ?
+                                                      (cur_dstat.duration_write_ms - dm->prev_dstat.duration_write_ms) /
+                                                      (dstat[i].operations[DEVSTAT_WRITE] -
+                                                       dm->prev_dstat.operations_write) :
+                                                      0);
+                                rrdset_done(dm->st_await);
+                            }
+
+                            // --------------------------------------------------------------------
+
+                            if(dm->do_avagsz == CONFIG_BOOLEAN_YES || (dm->do_avagsz == CONFIG_BOOLEAN_AUTO &&
+                                    (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+                                if (unlikely(!dm->st_avagsz)) {
+                                    dm->st_avagsz = rrdset_create_localhost("disk_avgsz",
+                                                                            disk,
+                                                                            NULL,
+                                                                            disk,
+                                                                            "disk.avgsz",
+                                                                            "Average Completed I/O Operation Bandwidth",
+                                                                            "kilobytes per operation",
+                                                                            2006,
+                                                                            update_every,
+                                                                            RRDSET_TYPE_AREA
+                                    );
+
+                                    rrdset_flag_set(dm->st_avagsz, RRDSET_FLAG_DETAIL);
+
+                                    dm->rd_avagsz_in  = rrddim_add(dm->st_avagsz, "reads",  NULL,  1, KILO_FACTOR,
+                                                                  RRD_ALGORITHM_ABSOLUTE);
+                                    dm->rd_avagsz_out = rrddim_add(dm->st_avagsz, "writes", NULL, -1, KILO_FACTOR,
+                                                                   RRD_ALGORITHM_ABSOLUTE);
+                                } else
+                                    rrdset_next(dm->st_avagsz);
+
+                                rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_in,
+                                                      (dstat[i].operations[DEVSTAT_READ] -
+                                                       dm->prev_dstat.operations_read) ?
+                                                      (dstat[i].bytes[DEVSTAT_READ] - dm->prev_dstat.bytes_read) /
+                                                      (dstat[i].operations[DEVSTAT_READ] -
+                                                       dm->prev_dstat.operations_read) :
+                                                      0);
+                                rrddim_set_by_pointer(dm->st_avagsz, dm->rd_avagsz_out,
+                                                      (dstat[i].operations[DEVSTAT_WRITE] -
+                                                       dm->prev_dstat.operations_write) ?
+                                                      (dstat[i].bytes[DEVSTAT_WRITE] - dm->prev_dstat.bytes_write) /
+                                                      (dstat[i].operations[DEVSTAT_WRITE] -
+                                                       dm->prev_dstat.operations_write) :
+                                                      0);
+                                rrdset_done(dm->st_avagsz);
+                            }
+
+                            // --------------------------------------------------------------------
+
+                            if(dm->do_svctm == CONFIG_BOOLEAN_YES || (dm->do_svctm == CONFIG_BOOLEAN_AUTO &&
+                                    (dstat[i].operations[DEVSTAT_READ] || dstat[i].operations[DEVSTAT_WRITE]))) {
+                                if (unlikely(!dm->st_svctm)) {
+                                    dm->st_svctm = rrdset_create_localhost("disk_svctm",
+                                                                           disk,
+                                                                           NULL,
+                                                                           disk,
+                                                                           "disk.svctm",
+                                                                           "Average Service Time",
+                                                                           "ms per operation",
+                                                                           2007,
+                                                                           update_every,
+                                                                           RRDSET_TYPE_LINE
+                                    );
+
+                                    rrdset_flag_set(dm->st_svctm, RRDSET_FLAG_DETAIL);
+
+                                    dm->rd_svctm = rrddim_add(dm->st_svctm, "svctm", NULL, 1, 1,
+                                                              RRD_ALGORITHM_ABSOLUTE);
+                                } else
+                                    rrdset_next(dm->st_svctm);
+
+                                rrddim_set_by_pointer(dm->st_svctm, dm->rd_svctm,
+                                    ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+                                     (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) ?
+                                    (cur_dstat.busy_time_ms - dm->prev_dstat.busy_time_ms) /
+                                    ((dstat[i].operations[DEVSTAT_READ] - dm->prev_dstat.operations_read) +
+                                     (dstat[i].operations[DEVSTAT_WRITE] - dm->prev_dstat.operations_write)) :
+                                    0);
+                                rrdset_done(dm->st_svctm);
+                            }
+
+                            // --------------------------------------------------------------------
+
+                            dm->prev_dstat.bytes_read        = dstat[i].bytes[DEVSTAT_READ];
+                            dm->prev_dstat.bytes_write       = dstat[i].bytes[DEVSTAT_WRITE];
+                            dm->prev_dstat.operations_read   = dstat[i].operations[DEVSTAT_READ];
+                            dm->prev_dstat.operations_write  = dstat[i].operations[DEVSTAT_WRITE];
+                            dm->prev_dstat.duration_read_ms  = cur_dstat.duration_read_ms;
+                            dm->prev_dstat.duration_write_ms = cur_dstat.duration_write_ms;
+                            dm->prev_dstat.busy_time_ms      = cur_dstat.busy_time_ms;
+                        }
+                    }
+                }
+
+                // --------------------------------------------------------------------
+
+                if (likely(do_system_io)) {
+                    static RRDSET *st = NULL;
+                    static RRDDIM *rd_in = NULL, *rd_out = NULL;
+
+                    if (unlikely(!st)) {
+                        st = rrdset_create_localhost("system",
+                                                     "io",
+                                                     NULL,
+                                                     "disk",
+                                                     NULL,
+                                                     "Disk I/O",
+                                                     "kilobytes/s",
+                                                     150,
+                                                     update_every,
+                                                     RRDSET_TYPE_AREA
+                        );
+
+                        rd_in  = rrddim_add(st, "in",  NULL,  1, 1, RRD_ALGORITHM_INCREMENTAL);
+                        rd_out = rrddim_add(st, "out", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+                    } else
+                        rrdset_next(st);
+
+                    rrddim_set_by_pointer(st, rd_in,  total_disk_kbytes_read);
+                    rrddim_set_by_pointer(st, rd_out, total_disk_kbytes_write);
+                    rrdset_done(st);
+                }
+            }
+        }
+        if (unlikely(common_error)) {
+            do_system_io = 0;
+            error("DISABLED: system.io chart");
+            do_io = 0;
+            error("DISABLED: disk.* charts");
+            do_ops = 0;
+            error("DISABLED: disk_ops.* charts");
+            do_qops = 0;
+            error("DISABLED: disk_qops.* charts");
+            do_util = 0;
+            error("DISABLED: disk_util.* charts");
+            do_iotime = 0;
+            error("DISABLED: disk_iotime.* charts");
+            do_await = 0;
+            error("DISABLED: disk_await.* charts");
+            do_avagsz = 0;
+            error("DISABLED: disk_avgsz.* charts");
+            do_svctm = 0;
+            error("DISABLED: disk_svctm.* charts");
+            error("DISABLED: kern.devstat module");
+            return 1;
+        }
+    } else {
+        error("DISABLED: kern.devstat module");
+        return 1;
     }
 
     return 0;
index 2ccdf6801480d2064390513bf0616be47c71a7f7..8575061ac1fd31222a3100bec09bd78294b890b8 100644 (file)
@@ -129,11 +129,19 @@ void global_statistics_charts(void) {
     getrusage(RUSAGE_THREAD, &thread);
     getrusage(RUSAGE_SELF, &me);
 
+#ifdef __FreeBSD__
+    if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_freebsd_cpu");
+    if (!stcpu_thread) {
+        stcpu_thread = rrdset_create_localhost("netdata", "plugin_freebsd_cpu", NULL, "freebsd", NULL
+                                               , "NetData FreeBSD Plugin CPU usage", "milliseconds/s", 132000
+                                               , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#else
     if (!stcpu_thread) stcpu_thread = rrdset_find_localhost("netdata.plugin_proc_cpu");
     if (!stcpu_thread) {
         stcpu_thread = rrdset_create_localhost("netdata", "plugin_proc_cpu", NULL, "proc", NULL
                                                , "NetData Proc Plugin CPU usage", "milliseconds/s", 132000
                                                , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+#endif
 
         rrddim_add(stcpu_thread, "user", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
         rrddim_add(stcpu_thread, "system", NULL, 1, 1000, RRD_ALGORITHM_INCREMENTAL);
index f43789de20265c1c5dd80c07b26e2ce2057f1859..af229fb61eb2c6d35e6dea74b68dcf8c727c7510 100644 (file)
@@ -210,7 +210,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
 
     if (next_loadavg_dt <= dt) {
         if (likely(do_loadavg)) {
-            if (unlikely(GETSYSCTL("vm.loadavg", sysload))) {
+            if (unlikely(GETSYSCTL_BY_NAME("vm.loadavg", sysload))) {
                 do_loadavg = 0;
                 error("DISABLED: system.load");
             } else {
@@ -240,7 +240,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     // --------------------------------------------------------------------
 
     if (likely(do_swap)) {
-        if (unlikely(GETSYSCTL("vm.swapusage", swap_usage))) {
+        if (unlikely(GETSYSCTL_BY_NAME("vm.swapusage", swap_usage))) {
             do_swap = 0;
             error("DISABLED: system.swap");
         } else {
@@ -315,7 +315,7 @@ 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))){
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet.tcp.stats", tcpstat))){
             do_tcp_packets = 0;
             error("DISABLED: ipv4.tcppackets");
             do_tcp_errors = 0;
@@ -480,7 +480,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
 
     // 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))) {
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet.udp.stats", udpstat))) {
             do_udp_packets = 0;
             error("DISABLED: ipv4.udppackets");
             do_udp_errors = 0;
@@ -532,7 +532,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     // --------------------------------------------------------------------
 
     if (likely(do_icmp_packets || do_icmpmsg)) {
-        if (unlikely(GETSYSCTL("net.inet.icmp.stats", icmpstat))) {
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet.icmp.stats", icmpstat))) {
             do_icmp_packets = 0;
             error("DISABLED: ipv4.icmp");
             error("DISABLED: ipv4.icmp_errors");
@@ -612,7 +612,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
 
     // 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))) {
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet.ip.stats", ipstat))) {
             do_ip_packets = 0;
             error("DISABLED: ipv4.packets");
             do_ip_fragsout = 0;
@@ -718,7 +718,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     // --------------------------------------------------------------------
 
     if (likely(do_ip6_packets || do_ip6_fragsout || do_ip6_fragsin || do_ip6_errors)) {
-        if (unlikely(GETSYSCTL("net.inet6.ip6.stats", ip6stat))) {
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet6.ip6.stats", ip6stat))) {
             do_ip6_packets = 0;
             error("DISABLED: ipv6.packets");
             do_ip6_fragsout = 0;
@@ -850,7 +850,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     // --------------------------------------------------------------------
 
     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))) {
+        if (unlikely(GETSYSCTL_BY_NAME("net.inet6.icmp6.stats", icmp6stat))) {
             do_icmp6 = 0;
             error("DISABLED: ipv6.icmp");
         } else {
@@ -1073,7 +1073,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     // --------------------------------------------------------------------
 
     if (likely(do_uptime)) {
-        if (unlikely(GETSYSCTL("kern.boottime", boot_time))) {
+        if (unlikely(GETSYSCTL_BY_NAME("kern.boottime", boot_time))) {
             do_uptime = 0;
             error("DISABLED: system.uptime");
         } else {
@@ -1095,7 +1095,7 @@ int do_macos_sysctl(int update_every, usec_t dt) {
     return 0;
 }
 
-int getsysctl(const char *name, void *ptr, size_t len)
+int getsysctl_by_name(const char *name, void *ptr, size_t len)
 {
     size_t nlen = len;
 
index a72585e28377a1157bcae85459bc73176b14d8d3..e3d78c4a3218faf11bab39b8c91456ad2bfcaa71 100644 (file)
@@ -299,6 +299,8 @@ void help(int exitcode) {
             "  -W stacksize=N           Set the stacksize (in bytes).\n\n"
             "  -W debug_flags=N         Set runtime tracing to debug.log.\n\n"
             "  -W unittest              Run internal unittests and exit.\n\n"
+            "  -W set section option value\n"
+            "                           set netdata.conf option from the command line.\n\n"
             "  -W simple-pattern pattern string\n"
             "                           Check if string matches pattern and exit.\n\n"
     );
@@ -625,6 +627,7 @@ int main(int argc, char **argv) {
                     {
                         char* stacksize_string = "stacksize=";
                         char* debug_flags_string = "debug_flags=";
+
                         if(strcmp(optarg, "unittest") == 0) {
                             default_rrd_update_every = 1;
                             default_rrd_memory_mode = RRD_MEMORY_MODE_RAM;
@@ -691,9 +694,44 @@ int main(int argc, char **argv) {
                             config_set(CONFIG_SECTION_GLOBAL, "debug flags",  optarg);
                             debug_flags = strtoull(optarg, NULL, 0);
                         }
+                        else if(strcmp(optarg, "set") == 0) {
+                            if(optind + 3 > argc) {
+                                fprintf(stderr, "%s", "\nUSAGE: -W set 'section' 'key' 'value'\n\n"
+                                        " Overwrites settings of netdata.conf.\n"
+                                        "\n"
+                                        " These options interact with: -c netdata.conf\n"
+                                        " If -c netdata.conf is given on the command line,\n"
+                                        " before -W set... the user may overwrite command\n"
+                                        " line parameters at netdata.conf\n"
+                                        " If -c netdata.conf is given after (or missing)\n"
+                                        " -W set... the user cannot overwrite the command line\n"
+                                        " parameters."
+                                        "\n"
+                                );
+                                exit(1);
+                            }
+                            const char *section = argv[optind];
+                            const char *key = argv[optind + 1];
+                            const char *value = argv[optind + 2];
+                            optind += 3;
+
+                            // set this one as the default
+                            // only if it is not already set in the config file
+                            // so the caller can use -c netdata.conf before or
+                            // after this parameter to prevent or allow overwriting
+                            // variables at netdata.conf
+                            config_set_default(section, key,  value);
+
+                            // fprintf(stderr, "SET section '%s', key '%s', value '%s'\n", section, key, value);
+                        }
+                        else {
+                            fprintf(stderr, "Unknown -W parameter '%s'\n", optarg);
+                            help(1);
+                        }
                     }
                     break;
                 default: /* ? */
+                    fprintf(stderr, "Unknown parameter '%c'\n", opt);
                     help(1);
                     break;
             }
index 3490e70edef2f587d758ce0bb1adf61ecb6a77db..31ab6e0c44d7529b376ab355e11b62f506bb6668 100644 (file)
@@ -1,5 +1,62 @@
 #include "common.h"
 
+static struct freebsd_module {
+    const char *name;
+    const char *dim;
+
+    int enabled;
+
+    int (*func)(int update_every, usec_t dt);
+    usec_t duration;
+
+    RRDDIM *rd;
+
+} freebsd_modules[] = {
+
+        // system metrics
+        { .name = "kern.cp_time",          .dim = "cp_time",        .enabled = 1, .func = do_kern_cp_time },
+        { .name = "vm.loadavg",            .dim = "loadavg",        .enabled = 1, .func = do_vm_loadavg },
+        { .name = "system.ram",            .dim = "system_ram",     .enabled = 1, .func = do_system_ram },
+        { .name = "vm.swap_info",          .dim = "swap",           .enabled = 1, .func = do_vm_swap_info },
+        { .name = "vm.stats.vm.v_swappgs", .dim = "swap_io",        .enabled = 1, .func = do_vm_stats_sys_v_swappgs },
+        { .name = "vm.vmtotal",            .dim = "vmtotal",        .enabled = 1, .func = do_vm_vmtotal },
+        { .name = "vm.stats.vm.v_forks",   .dim = "forks",          .enabled = 1, .func = do_vm_stats_sys_v_forks },
+        { .name = "vm.stats.sys.v_swtch",  .dim = "context_swtch",  .enabled = 1, .func = do_vm_stats_sys_v_swtch },
+        { .name = "hw.intrcnt",            .dim = "hw_intr",        .enabled = 1, .func = do_hw_intcnt },
+        { .name = "vm.stats.sys.v_intr",   .dim = "dev_intr",       .enabled = 1, .func = do_vm_stats_sys_v_intr },
+        { .name = "vm.stats.sys.v_soft",   .dim = "soft_intr",      .enabled = 1, .func = do_vm_stats_sys_v_soft },
+        { .name = "net.isr",               .dim = "net_isr",        .enabled = 1, .func = do_net_isr },
+        { .name = "kern.ipc.sem",          .dim = "semaphores",     .enabled = 1, .func = do_kern_ipc_sem },
+        { .name = "kern.ipc.shm",          .dim = "shared_memory",  .enabled = 1, .func = do_kern_ipc_shm },
+        { .name = "kern.ipc.msq",          .dim = "message_queues", .enabled = 1, .func = do_kern_ipc_msq },
+        { .name = "uptime",                .dim = "uptime",         .enabled = 1, .func = do_uptime },
+
+        // memory metrics
+        { .name = "vm.stats.vm.v_pgfaults", .dim = "pgfaults",      .enabled = 1, .func = do_vm_stats_sys_v_pgfaults },
+
+        // CPU metrics
+        { .name = "kern.cp_times",         .dim = "cp_times",       .enabled = 1, .func = do_kern_cp_times },
+
+        // disk metrics
+        { .name = "kern.devstat",          .dim = "kern_devstat",   .enabled = 1, .func = do_kern_devstat },
+        { .name = "getmntinfo",            .dim = "getmntinfo",     .enabled = 1, .func = do_getmntinfo },
+
+        // network metrics
+        { .name = "net.inet.tcp.states",   .dim = "tcp_states",     .enabled = 1, .func = do_net_inet_tcp_states },
+        { .name = "net.inet.tcp.stats",    .dim = "tcp_stats",      .enabled = 1, .func = do_net_inet_tcp_stats },
+        { .name = "net.inet.udp.stats",    .dim = "udp_stats",      .enabled = 1, .func = do_net_inet_udp_stats },
+        { .name = "net.inet.icmp.stats",   .dim = "icmp_stats",     .enabled = 1, .func = do_net_inet_icmp_stats },
+        { .name = "net.inet.ip.stats",     .dim = "ip_stats",       .enabled = 1, .func = do_net_inet_ip_stats },
+        { .name = "net.inet6.ip6.stats",   .dim = "ip6_stats",      .enabled = 1, .func = do_net_inet6_ip6_stats },
+        { .name = "net.inet6.icmp6.stats", .dim = "icmp6_stats",    .enabled = 1, .func = do_net_inet6_icmp6_stats },
+
+        // network interfaces metrics
+        { .name = "getifaddrs",            .dim = "getifaddrs",   .enabled = 1, .func = do_getifaddrs },
+
+        // the terminator of this array
+        { .name = NULL, .dim = NULL, .enabled = 0, .func = NULL }
+};
+
 void *freebsd_main(void *ptr) {
     struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
 
@@ -11,34 +68,80 @@ void *freebsd_main(void *ptr) {
     if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
         error("Cannot set pthread cancel state to ENABLE.");
 
-    // when ZERO, attempt to do it
-    int vdo_cpu_netdata             = !config_get_boolean("plugin:freebsd", "netdata server resources", 1);
-    int vdo_freebsd_sysctl          = !config_get_boolean("plugin:freebsd", "sysctl", 1);
+    int vdo_cpu_netdata = config_get_boolean("plugin:freebsd", "netdata server resources", 1);
+
+    // initialize FreeBSD plugin
+    if (freebsd_plugin_init())
+        netdata_exit = 1;
 
-    // keep track of the time each module was called
-    unsigned long long sutime_freebsd_sysctl = 0ULL;
+    // check the enabled status for each module
+    int i;
+    for(i = 0 ; freebsd_modules[i].name ;i++) {
+        struct freebsd_module *pm = &freebsd_modules[i];
+
+        pm->enabled = config_get_boolean("plugin:freebsd", pm->name, pm->enabled);
+        pm->duration = 0ULL;
+        pm->rd = NULL;
+    }
 
     usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
     heartbeat_t hb;
     heartbeat_init(&hb);
+
     for(;;) {
         usec_t hb_dt = heartbeat_next(&hb, step);
+        usec_t duration = 0ULL;
 
         if(unlikely(netdata_exit)) break;
 
         // BEGIN -- the job to be done
 
-        if(!vdo_freebsd_sysctl) {
-            debug(D_PROCNETDEV_LOOP, "FREEBSD: calling do_freebsd_sysctl().");
-            vdo_freebsd_sysctl = do_freebsd_sysctl(localhost->rrd_update_every, hb_dt);
+        for(i = 0 ; freebsd_modules[i].name ;i++) {
+            struct freebsd_module *pm = &freebsd_modules[i];
+            if(unlikely(!pm->enabled)) continue;
+
+            debug(D_PROCNETDEV_LOOP, "FREEBSD calling %s.", pm->name);
+
+            pm->enabled = !pm->func(localhost->rrd_update_every, hb_dt);
+            pm->duration = heartbeat_dt_usec(&hb) - duration;
+            duration += pm->duration;
+
+            if(unlikely(netdata_exit)) break;
         }
-        if(unlikely(netdata_exit)) break;
 
         // END -- the job is done
 
         // --------------------------------------------------------------------
 
-        if(!vdo_cpu_netdata) {
+        if(vdo_cpu_netdata) {
+            static RRDSET *st = NULL;
+
+            if(unlikely(!st)) {
+                st = rrdset_find_bytype_localhost("netdata", "plugin_freebsd_modules");
+
+                if(!st) {
+                    st = rrdset_create_localhost("netdata", "plugin_freebsd_modules", NULL, "freebsd", NULL
+                    , "NetData FreeBSD Plugin Modules Durations", "milliseconds/run", 132001
+                    , localhost->rrd_update_every, RRDSET_TYPE_STACKED);
+
+                    for(i = 0 ; freebsd_modules[i].name ;i++) {
+                        struct freebsd_module *pm = &freebsd_modules[i];
+                        if(unlikely(!pm->enabled)) continue;
+
+                        pm->rd = rrddim_add(st, pm->dim, NULL, 1, 1000, RRD_ALGORITHM_ABSOLUTE);
+                    }
+                }
+            }
+            else rrdset_next(st);
+
+            for(i = 0 ; freebsd_modules[i].name ;i++) {
+                struct freebsd_module *pm = &freebsd_modules[i];
+                if(unlikely(!pm->enabled)) continue;
+
+                rrddim_set_by_pointer(st, pm->rd, pm->duration);
+            }
+            rrdset_done(st);
+
             global_statistics_charts();
             registry_statistics();
         }
index 3a1ac39100ff884171bfcb5bdb0a7b3b7afa6e96..166c64338b206d34654a2d88ed38cac29b390fc4 100644 (file)
 
 #include <sys/sysctl.h>
 
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
-
 void *freebsd_main(void *ptr);
 
-extern int do_freebsd_sysctl(int update_every, usec_t dt);
+extern int freebsd_plugin_init();
+
+extern int do_vm_loadavg(int update_every, usec_t dt);
+extern int do_vm_vmtotal(int update_every, usec_t dt);
+extern int do_kern_cp_time(int update_every, usec_t dt);
+extern int do_kern_cp_times(int update_every, usec_t dt);
+extern int do_hw_intcnt(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_intr(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_soft(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swtch(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_forks(int update_every, usec_t dt);
+extern int do_vm_swap_info(int update_every, usec_t dt);
+extern int do_system_ram(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_swappgs(int update_every, usec_t dt);
+extern int do_vm_stats_sys_v_pgfaults(int update_every, usec_t dt);
+extern int do_kern_ipc_sem(int update_every, usec_t dt);
+extern int do_kern_ipc_shm(int update_every, usec_t dt);
+extern int do_kern_ipc_msq(int update_every, usec_t dt);
+extern int do_uptime(int update_every, usec_t dt);
+extern int do_net_isr(int update_every, usec_t dt);
+extern int do_net_inet_tcp_states(int update_every, usec_t dt);
+extern int do_net_inet_tcp_stats(int update_every, usec_t dt);
+extern int do_net_inet_udp_stats(int update_every, usec_t dt);
+extern int do_net_inet_icmp_stats(int update_every, usec_t dt);
+extern int do_net_inet_ip_stats(int update_every, usec_t dt);
+extern int do_net_inet6_ip6_stats(int update_every, usec_t dt);
+extern int do_net_inet6_icmp6_stats(int update_every, usec_t dt);
+extern int do_getifaddrs(int update_every, usec_t dt);
+extern int do_getmntinfo(int update_every, usec_t dt);
+extern int do_kern_devstat(int update_every, usec_t dt);
+
+#define GETSYSCTL_MIB(name, mib) getsysctl_mib(name, mib, sizeof(mib)/sizeof(int))
+
+static inline int getsysctl_mib(const char *name, int *mib, size_t len)
+{
+    size_t nlen = len;
+
+    if (unlikely(sysctlnametomib(name, mib, &nlen) == -1)) {
+        error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+        return 1;
+    }
+    if (unlikely(nlen != len)) {
+        error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+        return 1;
+    }
+    return 0;
+}
+
+#define GETSYSCTL_SIMPLE(name, mib, var) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), &(var), sizeof(var))
+#define GETSYSCTL_WSIZE(name, mib, var, size) getsysctl_simple(name, mib, sizeof(mib)/sizeof(int), var, size)
+
+static inline int getsysctl_simple(const char *name, int *mib, size_t miblen, void *ptr, size_t len)
+{
+    size_t nlen = len;
+
+    if (unlikely(!mib[0]))
+        if (unlikely(getsysctl_mib(name, mib, miblen)))
+            return 1;
+
+    if (unlikely(sysctl(mib, miblen, ptr, &nlen, NULL, 0) == -1)) {
+        error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+        return 1;
+    }
+    if (unlikely(nlen != len)) {
+        error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)len, (unsigned long)nlen);
+        return 1;
+    }
+
+    return 0;
+}
+
+#define GETSYSCTL_SIZE(name, mib, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), NULL, &(size))
+#define GETSYSCTL(name, mib, var, size) getsysctl(name, mib, sizeof(mib)/sizeof(int), &(var), &(size))
+
+static inline int getsysctl(const char *name, int *mib, size_t miblen, void *ptr, size_t *len)
+{
+    size_t nlen = *len;
+
+    if (unlikely(!mib[0]))
+        if (unlikely(getsysctl_mib(name, mib, miblen)))
+            return 1;
+
+    if (unlikely(sysctl(mib, miblen, ptr, len, NULL, 0) == -1)) {
+        error("FREEBSD: sysctl(%s...) failed: %s", name, strerror(errno));
+        return 1;
+    }
+    if (unlikely(ptr != NULL && nlen != *len)) {
+        error("FREEBSD: sysctl(%s...) expected %lu, got %lu", name, (unsigned long)*len, (unsigned long)nlen);
+        return 1;
+    }
+
+    return 0;
+}
+
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
 
-static inline int getsysctl(const char *name, void *ptr, size_t len)
+static inline int getsysctl_by_name(const char *name, void *ptr, size_t len)
 {
     size_t nlen = len;
 
index a21e5601de13faed21661b7ca51d76f2283640ba..6ccf3e8611d8763955df037ff9407f9afadb8063 100644 (file)
@@ -3,9 +3,9 @@
 
 void *macos_main(void *ptr);
 
-#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+#define GETSYSCTL_BY_NAME(name, var) getsysctl_by_name(name, &(var), sizeof(var))
 
-extern int getsysctl(const char *name, void *ptr, size_t len);
+extern int getsysctl_by_name(const char *name, void *ptr, size_t len);
 
 extern int do_macos_sysctl(int update_every, usec_t dt);
 extern int do_macos_mach_smi(int update_every, usec_t dt);
index a9e6ebc97d5352304cae9b1e738a104ec5c3dacc..4c691be055eab6b5eb0065b55f59d27a528cf52d 100644 (file)
 #include "common.h"
 
 #ifdef INTERNAL_PLUGIN_NFACCT
+
+#ifdef HAVE_LIBMNL
 #include <libmnl/libmnl.h>
-#include <libnetfilter_acct/libnetfilter_acct.h>
 
-struct mynfacct {
-    const char *name;
-    uint64_t pkts;
-    uint64_t bytes;
-    struct nfacct *nfacct;
+static inline size_t mnl_buffer_size() {
+    long s = MNL_SOCKET_BUFFER_SIZE;
+    if(s <= 0) return 8192;
+    return (size_t)s;
+}
+
+// ----------------------------------------------------------------------------
+// DO_NFSTAT - collect netfilter connection tracker statistics via netlink
+// example: https://github.com/formorer/pkg-conntrack-tools/blob/master/src/conntrack.c
+
+#ifdef HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
+#define DO_NFSTAT 1
+
+#define RRD_TYPE_NET_STAT_NETFILTER "netfilter"
+#define RRD_TYPE_NET_STAT_CONNTRACK "netlink" // FIXME: should be "conntrack" when merged with the /proc plugin
+
+#include <linux/netfilter/nfnetlink_conntrack.h>
+
+static struct {
+    int update_every;
+    char *buf;
+    size_t buf_size;
+    struct mnl_socket *mnl;
+    struct nlmsghdr *nlh;
+    struct nfgenmsg *nfh;
+    unsigned int seq;
+    uint32_t portid;
+
+    struct nlattr *tb[CTA_STATS_MAX+1];
+    const char *attr2name[CTA_STATS_MAX+1];
+    kernel_uint_t metrics[CTA_STATS_MAX+1];
+
+    struct nlattr *tb_exp[CTA_STATS_EXP_MAX+1];
+    const char *attr2name_exp[CTA_STATS_EXP_MAX+1];
+    kernel_uint_t metrics_exp[CTA_STATS_EXP_MAX+1];
+} nfstat_root = {
+        .update_every = 1,
+        .buf = NULL,
+        .buf_size = 0,
+        .mnl = NULL,
+        .nlh = NULL,
+        .nfh = NULL,
+        .seq = 0,
+        .portid = 0,
+        .tb = {},
+        .attr2name = {
+                [CTA_STATS_SEARCHED]      = "searched",
+                [CTA_STATS_FOUND]             = "found",
+                [CTA_STATS_NEW]                       = "new",
+                [CTA_STATS_INVALID]           = "invalid",
+                [CTA_STATS_IGNORE]            = "ignore",
+                [CTA_STATS_DELETE]            = "delete",
+                [CTA_STATS_DELETE_LIST]           = "delete_list",
+                [CTA_STATS_INSERT]            = "insert",
+                [CTA_STATS_INSERT_FAILED]  = "insert_failed",
+                [CTA_STATS_DROP]              = "drop",
+                [CTA_STATS_EARLY_DROP]    = "early_drop",
+                [CTA_STATS_ERROR]             = "icmp_error",
+                [CTA_STATS_SEARCH_RESTART] = "search_restart",
+        },
+        .metrics = {},
+        .tb_exp = {},
+        .attr2name_exp = {
+                [CTA_STATS_EXP_NEW]           = "new",
+                [CTA_STATS_EXP_CREATE]    = "created",
+                [CTA_STATS_EXP_DELETE]    = "deleted",
+        },
+        .metrics_exp = {}
 };
 
-struct nfacct_list {
-    int size;
-    int len;
-    struct mynfacct data[];
-} *nfacct_list = NULL;
 
-static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
-    if(data) {};
+static int nfstat_init(int update_every) {
+    nfstat_root.update_every = update_every;
 
-    if(!nfacct_list || nfacct_list->len == nfacct_list->size) {
-        int size = (nfacct_list) ? nfacct_list->size : 0;
-        int len = (nfacct_list) ? nfacct_list->len : 0;
-        size++;
+    nfstat_root.buf_size = mnl_buffer_size();
+    nfstat_root.buf = mallocz(nfstat_root.buf_size);
 
-        info("nfacct.plugin: increasing nfacct_list to size %d", size);
+    nfstat_root.mnl  = mnl_socket_open(NETLINK_NETFILTER);
+    if(!nfstat_root.mnl) {
+        error("NFSTAT: mnl_socket_open() failed");
+        return 1;
+    }
 
-        nfacct_list = reallocz(nfacct_list, sizeof(struct nfacct_list) + (sizeof(struct mynfacct) * size));
+    nfstat_root.seq = (unsigned int)now_realtime_sec() - 1;
 
-        nfacct_list->data[len].nfacct = nfacct_alloc();
-        if(!nfacct_list->data[size - 1].nfacct) {
-            error("nfacct.plugin: nfacct_alloc() failed.");
-            free(nfacct_list);
-            nfacct_list = NULL;
-            return MNL_CB_OK;
-        }
+    if(mnl_socket_bind(nfstat_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+        error("NFSTAT: mnl_socket_bind() failed");
+        return 1;
+    }
+    nfstat_root.portid = mnl_socket_get_portid(nfstat_root.mnl);
+
+    return 0;
+}
 
-        nfacct_list->size = size;
-        nfacct_list->len = len;
+static void nfstat_cleanup() {
+    if(nfstat_root.mnl) {
+        mnl_socket_close(nfstat_root.mnl);
+        nfstat_root.mnl = NULL;
     }
 
-    if(nfacct_nlmsg_parse_payload(nlh, nfacct_list->data[nfacct_list->len].nfacct) < 0) {
-        error("nfacct.plugin: nfacct_nlmsg_parse_payload() failed.");
+    freez(nfstat_root.buf);
+    nfstat_root.buf = NULL;
+    nfstat_root.buf_size = 0;
+}
+
+static struct nlmsghdr * nfct_mnl_nlmsghdr_put(char *buf, uint16_t subsys, uint16_t type, uint8_t family, uint32_t seq) {
+    struct nlmsghdr *nlh;
+    struct nfgenmsg *nfh;
+
+    nlh = mnl_nlmsg_put_header(buf);
+    nlh->nlmsg_type = (subsys << 8) | type;
+    nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_DUMP;
+    nlh->nlmsg_seq = seq;
+
+    nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg));
+    nfh->nfgen_family = family;
+    nfh->version = NFNETLINK_V0;
+    nfh->res_id = 0;
+
+    return nlh;
+}
+
+static int nfct_stats_attr_cb(const struct nlattr *attr, void *data) {
+    const struct nlattr **tb = data;
+    int type = mnl_attr_get_type(attr);
+
+    if (mnl_attr_type_valid(attr, CTA_STATS_MAX) < 0)
         return MNL_CB_OK;
+
+    if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+        error("NFSTAT: mnl_attr_validate() failed");
+        return MNL_CB_ERROR;
     }
 
-    nfacct_list->data[nfacct_list->len].name  = nfacct_attr_get_str(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_NAME);
-    nfacct_list->data[nfacct_list->len].pkts  = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_PKTS);
-    nfacct_list->data[nfacct_list->len].bytes = nfacct_attr_get_u64(nfacct_list->data[nfacct_list->len].nfacct, NFACCT_ATTR_BYTES);
+    tb[type] = attr;
+    return MNL_CB_OK;
+}
+
+static int nfstat_callback(const struct nlmsghdr *nlh, void *data) {
+    (void)data;
+
+    struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+    mnl_attr_parse(nlh, sizeof(*nfg), nfct_stats_attr_cb, nfstat_root.tb);
+
+    // printf("cpu=%-4u\t", ntohs(nfg->res_id));
+
+    int i;
+    // add the metrics of this CPU into the metrics
+    for (i = 0; i < CTA_STATS_MAX+1; i++) {
+        if (nfstat_root.tb[i]) {
+            // printf("%s=%u ", nfstat_root.attr2name[i], ntohl(mnl_attr_get_u32(nfstat_root.tb[i])));
+            nfstat_root.metrics[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb[i]));
+        }
+    }
+    // printf("\n");
 
-    nfacct_list->len++;
     return MNL_CB_OK;
 }
 
-void *nfacct_main(void *ptr) {
-    struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+static int nfstat_collect_conntrack() {
+    // zero all metrics - we will sum the metrics of all CPUs later
+    int i;
+    for (i = 0; i < CTA_STATS_MAX+1; i++)
+        nfstat_root.metrics[i] = 0;
 
-    info("NFACCT thread created with task id %d", gettid());
+    // prepare the request
+    nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK, IPCTNL_MSG_CT_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
 
-    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
-        error("nfacct.plugin: Cannot set pthread cancel type to DEFERRED.");
+    // send the request
+    if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+        error("NFSTAT: mnl_socket_sendto() failed");
+        return 1;
+    }
 
-    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
-        error("nfacct.plugin: Cannot set pthread cancel state to ENABLE.");
+    // get the reply
+    ssize_t ret;
+    while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+        if(mnl_cb_run(
+                nfstat_root.buf
+                , (size_t)ret
+                , nfstat_root.nlh->nlmsg_seq
+                , nfstat_root.portid
+                , nfstat_callback
+                , NULL
+        ) <= MNL_CB_STOP)
+            break;
+    }
+
+    // verify we run without issues
+    if (ret == -1) {
+        error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+        return 1;
+    }
 
-    char buf[MNL_SOCKET_BUFFER_SIZE];
-    struct mnl_socket *nl = NULL;
-    struct nlmsghdr *nlh = NULL;
-    unsigned int seq = 0, portid = 0;
+    return 0;
+}
 
-    seq = now_realtime_sec() - 1;
+static int nfexp_stats_attr_cb(const struct nlattr *attr, void *data)
+{
+    const struct nlattr **tb = data;
+    int type = mnl_attr_get_type(attr);
 
-    nl  = mnl_socket_open(NETLINK_NETFILTER);
-    if(!nl) {
-        error("nfacct.plugin: mnl_socket_open() failed");
-        goto cleanup;
+    if (mnl_attr_type_valid(attr, CTA_STATS_EXP_MAX) < 0)
+        return MNL_CB_OK;
+
+    if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
+        error("NFSTAT EXP: mnl_attr_validate() failed");
+        return MNL_CB_ERROR;
     }
 
-    if(mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
-        error("nfacct.plugin: mnl_socket_bind() failed");
-        goto cleanup;
+    tb[type] = attr;
+    return MNL_CB_OK;
+}
+
+static int nfstat_callback_exp(const struct nlmsghdr *nlh, void *data) {
+    (void)data;
+
+    struct nfgenmsg *nfg = mnl_nlmsg_get_payload(nlh);
+
+    mnl_attr_parse(nlh, sizeof(*nfg), nfexp_stats_attr_cb, nfstat_root.tb_exp);
+
+    int i;
+    for (i = 0; i < CTA_STATS_EXP_MAX+1; i++) {
+        if (nfstat_root.tb_exp[i]) {
+            nfstat_root.metrics_exp[i] += ntohl(mnl_attr_get_u32(nfstat_root.tb_exp[i]));
+        }
     }
-    portid = mnl_socket_get_portid(nl);
 
-    // ------------------------------------------------------------------------
+    return MNL_CB_OK;
+}
 
-    struct timeval last, now;
-    usec_t usec = 0, susec = 0;
-    RRDSET *st = NULL;
+static int nfstat_collect_conntrack_expectations() {
+    // zero all metrics - we will sum the metrics of all CPUs later
+    int i;
+    for (i = 0; i < CTA_STATS_EXP_MAX+1; i++)
+        nfstat_root.metrics_exp[i] = 0;
 
-    now_realtime_timeval(&last);
+    // prepare the request
+    nfstat_root.nlh = nfct_mnl_nlmsghdr_put(nfstat_root.buf, NFNL_SUBSYS_CTNETLINK_EXP, IPCTNL_MSG_EXP_GET_STATS_CPU, AF_UNSPEC, nfstat_root.seq);
 
-    // ------------------------------------------------------------------------
+    // send the request
+    if(mnl_socket_sendto(nfstat_root.mnl, nfstat_root.nlh, nfstat_root.nlh->nlmsg_len) < 0) {
+        error("NFSTAT: mnl_socket_sendto() failed");
+        return 1;
+    }
 
-    while(1) {
-        if(unlikely(netdata_exit)) break;
+    // get the reply
+    ssize_t ret;
+    while ((ret = mnl_socket_recvfrom(nfstat_root.mnl, nfstat_root.buf, nfstat_root.buf_size)) > 0) {
+        if(mnl_cb_run(
+                nfstat_root.buf
+                , (size_t)ret
+                , nfstat_root.nlh->nlmsg_seq
+                , nfstat_root.portid
+                , nfstat_callback_exp
+                , NULL
+        ) <= MNL_CB_STOP)
+            break;
+    }
 
-        seq++;
+    // verify we run without issues
+    if (ret == -1) {
+        error("NFSTAT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+        return 1;
+    }
+
+    return 0;
+}
+
+static int nfstat_collect() {
+    nfstat_root.seq++;
+
+    if(nfstat_collect_conntrack())
+        return 1;
+
+    if(nfstat_collect_conntrack_expectations())
+        return 1;
+
+    return 0;
+}
 
-        nlh = nfacct_nlmsg_build_hdr(buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, seq);
-        if(!nlh) {
-            error("nfacct.plugin: nfacct_nlmsg_build_hdr() failed");
-            goto cleanup;
+static void nfstat_send_metrics() {
+
+    {
+        static RRDSET *st_new = NULL;
+        static RRDDIM *rd_new = NULL, *rd_ignore = NULL, *rd_invalid = NULL;
+
+        if(!st_new) {
+            st_new = rrdset_create_localhost(
+                    RRD_TYPE_NET_STAT_NETFILTER
+                    , RRD_TYPE_NET_STAT_CONNTRACK "_new"
+                    , NULL
+                    , RRD_TYPE_NET_STAT_CONNTRACK
+                    , NULL
+                    , "Connection Tracker New Connections"
+                    , "connections/s"
+                    , 3001
+                    , nfstat_root.update_every
+                    , RRDSET_TYPE_LINE
+            );
+
+            rd_new     = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_ignore  = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_IGNORE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_invalid = rrddim_add(st_new, nfstat_root.attr2name[CTA_STATS_INVALID], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else
+            rrdset_next(st_new);
 
-        if(mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
-            error("nfacct.plugin: mnl_socket_send");
-            goto cleanup;
+        rrddim_set_by_pointer(st_new, rd_new, (collected_number) nfstat_root.metrics[CTA_STATS_NEW]);
+        rrddim_set_by_pointer(st_new, rd_ignore, (collected_number) nfstat_root.metrics[CTA_STATS_IGNORE]);
+        rrddim_set_by_pointer(st_new, rd_invalid, (collected_number) nfstat_root.metrics[CTA_STATS_INVALID]);
+
+        rrdset_done(st_new);
+    }
+
+    // ----------------------------------------------------------------
+
+    {
+        static RRDSET *st_changes = NULL;
+        static RRDDIM *rd_inserted = NULL, *rd_deleted = NULL, *rd_delete_list = NULL;
+
+        if(!st_changes) {
+            st_changes = rrdset_create_localhost(
+                    RRD_TYPE_NET_STAT_NETFILTER
+                    , RRD_TYPE_NET_STAT_CONNTRACK "_changes"
+                    , NULL
+                    , RRD_TYPE_NET_STAT_CONNTRACK
+                    , NULL
+                    , "Connection Tracker Changes"
+                    , "changes/s"
+                    , 3002
+                    , nfstat_root.update_every
+                    , RRDSET_TYPE_LINE
+            );
+            rrdset_flag_set(st_changes, RRDSET_FLAG_DETAIL);
+
+            rd_inserted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_INSERT], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_deleted = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_delete_list = rrddim_add(st_changes, nfstat_root.attr2name[CTA_STATS_DELETE_LIST], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else
+            rrdset_next(st_changes);
 
-        if(nfacct_list) nfacct_list->len = 0;
+        rrddim_set_by_pointer(st_changes, rd_inserted, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT]);
+        rrddim_set_by_pointer(st_changes, rd_deleted, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE]);
+        rrddim_set_by_pointer(st_changes, rd_delete_list, (collected_number) nfstat_root.metrics[CTA_STATS_DELETE_LIST]);
 
-        int ret;
-        while((ret = mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0) {
-            if((ret = mnl_cb_run(buf, ret, seq, portid, nfacct_callback, NULL)) <= 0) break;
+        rrdset_done(st_changes);
+    }
+
+    // ----------------------------------------------------------------
+
+    {
+        static RRDSET *st_search = NULL;
+        static RRDDIM *rd_searched = NULL, *rd_restarted = NULL, *rd_found = NULL;
+
+        if(!st_search) {
+            st_search = rrdset_create_localhost(
+                    RRD_TYPE_NET_STAT_NETFILTER
+                    , RRD_TYPE_NET_STAT_CONNTRACK "_search"
+                    , NULL
+                    , RRD_TYPE_NET_STAT_CONNTRACK
+                    , NULL
+                    , "Connection Tracker Searches"
+                    , "searches/s"
+                    , 3010
+                    , nfstat_root.update_every
+                    , RRDSET_TYPE_LINE
+            );
+            rrdset_flag_set(st_search, RRDSET_FLAG_DETAIL);
+
+            rd_searched = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCHED], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_restarted = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_SEARCH_RESTART], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_found = rrddim_add(st_search, nfstat_root.attr2name[CTA_STATS_FOUND], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else
+            rrdset_next(st_search);
+
+        rrddim_set_by_pointer(st_search, rd_searched, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCHED]);
+        rrddim_set_by_pointer(st_search, rd_restarted, (collected_number) nfstat_root.metrics[CTA_STATS_SEARCH_RESTART]);
+        rrddim_set_by_pointer(st_search, rd_found, (collected_number) nfstat_root.metrics[CTA_STATS_FOUND]);
 
-        if (ret == -1) {
-            error("nfacct.plugin: error communicating with kernel.");
-            goto cleanup;
+        rrdset_done(st_search);
+    }
+
+    // ----------------------------------------------------------------
+
+    {
+        static RRDSET *st_errors = NULL;
+        static RRDDIM *rd_error = NULL, *rd_insert_failed = NULL, *rd_drop = NULL, *rd_early_drop = NULL;
+
+        if(!st_errors) {
+            st_errors = rrdset_create_localhost(
+                    RRD_TYPE_NET_STAT_NETFILTER
+                    , RRD_TYPE_NET_STAT_CONNTRACK "_errors"
+                    , NULL
+                    , RRD_TYPE_NET_STAT_CONNTRACK
+                    , NULL
+                    , "Connection Tracker Errors"
+                    , "events/s"
+                    , 3005
+                    , nfstat_root.update_every
+                    , RRDSET_TYPE_LINE
+            );
+            rrdset_flag_set(st_errors, RRDSET_FLAG_DETAIL);
+
+            rd_error = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_ERROR], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_insert_failed = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_INSERT_FAILED], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_early_drop = rrddim_add(st_errors, nfstat_root.attr2name[CTA_STATS_EARLY_DROP], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
         }
+        else
+            rrdset_next(st_errors);
 
-        // --------------------------------------------------------------------
+        rrddim_set_by_pointer(st_errors, rd_error, (collected_number) nfstat_root.metrics[CTA_STATS_ERROR]);
+        rrddim_set_by_pointer(st_errors, rd_insert_failed, (collected_number) nfstat_root.metrics[CTA_STATS_INSERT_FAILED]);
+        rrddim_set_by_pointer(st_errors, rd_drop, (collected_number) nfstat_root.metrics[CTA_STATS_DROP]);
+        rrddim_set_by_pointer(st_errors, rd_early_drop, (collected_number) nfstat_root.metrics[CTA_STATS_EARLY_DROP]);
 
-        now_realtime_timeval(&now);
-        usec = dt_usec(&now, &last) - susec;
-        debug(D_NFACCT_LOOP, "nfacct.plugin: last loop took %llu usec (worked for %llu, sleeped for %llu).", usec + susec, usec, susec);
+        rrdset_done(st_errors);
+    }
 
-        if(usec < (default_rrd_update_every * 1000000ULL / 2ULL)) susec = (default_rrd_update_every * 1000000ULL) - usec;
-        else susec = default_rrd_update_every * 1000000ULL / 2ULL;
+    // ----------------------------------------------------------------
+
+    {
+        static RRDSET *st_expect = NULL;
+        static RRDDIM *rd_new = NULL, *rd_created = NULL, *rd_deleted = NULL;
+
+        if(!st_expect) {
+            st_expect = rrdset_create_localhost(
+                    RRD_TYPE_NET_STAT_NETFILTER
+                    , RRD_TYPE_NET_STAT_CONNTRACK "_expect"
+                    , NULL
+                    , RRD_TYPE_NET_STAT_CONNTRACK
+                    , NULL
+                    , "Connection Tracker Expectations"
+                    , "expectations/s"
+                    , 3003
+                    , nfstat_root.update_every
+                    , RRDSET_TYPE_LINE
+            );
+            rrdset_flag_set(st_expect, RRDSET_FLAG_DETAIL);
+
+            rd_created = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_CREATE], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_deleted = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_DELETE], NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
+            rd_new = rrddim_add(st_expect, nfstat_root.attr2name_exp[CTA_STATS_EXP_NEW], NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
+        }
+        else
+            rrdset_next(st_expect);
 
+        rrddim_set_by_pointer(st_expect, rd_created, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_CREATE]);
+        rrddim_set_by_pointer(st_expect, rd_deleted, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_DELETE]);
+        rrddim_set_by_pointer(st_expect, rd_new, (collected_number) nfstat_root.metrics_exp[CTA_STATS_EXP_NEW]);
 
-        // --------------------------------------------------------------------
+        rrdset_done(st_expect);
+    }
+
+}
+
+#endif // HAVE_LINUX_NETFILTER_NFNETLINK_CONNTRACK_H
 
-        if(nfacct_list && nfacct_list->len) {
-            int i;
 
-            st = rrdset_find_bytype("netfilter", "nfacct_packets");
-            if(!st) {
-                st = rrdset_create("netfilter", "nfacct_packets", NULL, "nfacct", NULL, "Netfilter Accounting Packets", "packets/s", 3206, default_rrd_update_every, RRDSET_TYPE_STACKED);
+// ----------------------------------------------------------------------------
+// DO_NFACCT - collect netfilter accounting statistics via netlink
 
-                for(i = 0; i < nfacct_list->len ; i++)
-                    rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+#ifdef HAVE_LIBNETFILTER_ACCT
+#define DO_NFACCT 1
+
+#include <libnetfilter_acct/libnetfilter_acct.h>
 
-            for(i = 0; i < nfacct_list->len ; i++) {
-                RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+struct nfacct_data {
+    char *name;
+    uint32_t hash;
 
-                if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
-                if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].pkts);
-            }
+    uint64_t pkts;
+    uint64_t bytes;
 
-            rrdset_done(st);
+    RRDDIM *rd_bytes;
+    RRDDIM *rd_packets;
 
-            // ----------------------------------------------------------------
+    int updated;
 
-            st = rrdset_find_bytype("netfilter", "nfacct_bytes");
-            if(!st) {
-                st = rrdset_create("netfilter", "nfacct_bytes", NULL, "nfacct", NULL, "Netfilter Accounting Bandwidth", "kilobytes/s", 3207, default_rrd_update_every, RRDSET_TYPE_STACKED);
+    struct nfacct_data *next;
+};
 
-                for(i = 0; i < nfacct_list->len ; i++)
-                    rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
-            }
-            else rrdset_next(st);
+static struct {
+    int update_every;
+    char *buf;
+    size_t buf_size;
+    struct mnl_socket *mnl;
+    struct nlmsghdr *nlh;
+    unsigned int seq;
+    uint32_t portid;
+    struct nfacct *nfacct_buffer;
+    struct nfacct_data *nfacct_metrics;
+} nfacct_root = {
+        .update_every = 1,
+        .buf = NULL,
+        .buf_size = 0,
+        .mnl = NULL,
+        .nlh = NULL,
+        .seq = 0,
+        .portid = 0,
+        .nfacct_buffer = NULL,
+        .nfacct_metrics = NULL
+};
 
-            for(i = 0; i < nfacct_list->len ; i++) {
-                RRDDIM *rd = rrddim_find(st, nfacct_list->data[i].name);
+static inline struct nfacct_data *nfacct_data_get(const char *name, uint32_t hash) {
+    struct nfacct_data *d = NULL, *last = NULL;
+    for(d = nfacct_root.nfacct_metrics; d ; last = d, d = d->next) {
+        if(unlikely(d->hash == hash && !strcmp(d->name, name)))
+            return d;
+    }
 
-                if(!rd) rd = rrddim_add(st, nfacct_list->data[i].name, NULL, 1, 1000 * default_rrd_update_every, RRD_ALGORITHM_INCREMENTAL);
-                if(rd) rrddim_set_by_pointer(st, rd, nfacct_list->data[i].bytes);
-            }
+    d = callocz(1, sizeof(struct nfacct_data));
+    d->name = strdupz(name);
+    d->hash = hash;
 
-            rrdset_done(st);
+    if(!last) {
+        d->next = nfacct_root.nfacct_metrics;
+        nfacct_root.nfacct_metrics = d;
+    }
+    else {
+        d->next = last->next;
+        last->next = d;
+    }
+
+    return d;
+}
+
+static int nfacct_init(int update_every) {
+    nfacct_root.update_every = update_every;
+
+    nfacct_root.buf_size = mnl_buffer_size();
+    nfacct_root.buf = mallocz(nfacct_root.buf_size);
+
+    nfacct_root.nfacct_buffer = nfacct_alloc();
+    if(!nfacct_root.nfacct_buffer) {
+        error("nfacct.plugin: nfacct_alloc() failed.");
+        return 0;
+    }
+
+    nfacct_root.seq = (unsigned int)now_realtime_sec() - 1;
+
+    nfacct_root.mnl  = mnl_socket_open(NETLINK_NETFILTER);
+    if(!nfacct_root.mnl) {
+        error("nfacct.plugin: mnl_socket_open() failed");
+        return 1;
+    }
+
+    if(mnl_socket_bind(nfacct_root.mnl, 0, MNL_SOCKET_AUTOPID) < 0) {
+        error("nfacct.plugin: mnl_socket_bind() failed");
+        return 1;
+    }
+    nfacct_root.portid = mnl_socket_get_portid(nfacct_root.mnl);
+
+    return 0;
+}
+
+static void nfacct_cleanup() {
+    if(nfacct_root.mnl) {
+        mnl_socket_close(nfacct_root.mnl);
+        nfacct_root.mnl = NULL;
+    }
+
+    if(nfacct_root.nfacct_buffer) {
+        nfacct_free(nfacct_root.nfacct_buffer);
+        nfacct_root.nfacct_buffer = NULL;
+    }
+
+    freez(nfacct_root.buf);
+    nfacct_root.buf = NULL;
+    nfacct_root.buf_size = 0;
+
+    // FIXME: cleanup the metrics linked list
+}
+
+static int nfacct_callback(const struct nlmsghdr *nlh, void *data) {
+    (void)data;
+
+    if(nfacct_nlmsg_parse_payload(nlh, nfacct_root.nfacct_buffer) < 0) {
+        error("NFACCT: nfacct_nlmsg_parse_payload() failed.");
+        return MNL_CB_OK;
+    }
+
+    const char *name = nfacct_attr_get_str(nfacct_root.nfacct_buffer, NFACCT_ATTR_NAME);
+    uint32_t hash = simple_hash(name);
+
+    struct nfacct_data *d = nfacct_data_get(name, hash);
+
+    d->pkts  = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_PKTS);
+    d->bytes = nfacct_attr_get_u64(nfacct_root.nfacct_buffer, NFACCT_ATTR_BYTES);
+    d->updated = 1;
+
+    return MNL_CB_OK;
+}
+
+static int nfacct_collect() {
+    // mark all old metrics as not-updated
+    struct nfacct_data *d;
+    for(d = nfacct_root.nfacct_metrics; d ; d = d->next)
+        d->updated = 0;
+
+    // prepare the request
+    nfacct_root.seq++;
+    nfacct_root.nlh = nfacct_nlmsg_build_hdr(nfacct_root.buf, NFNL_MSG_ACCT_GET, NLM_F_DUMP, (uint32_t)nfacct_root.seq);
+    if(!nfacct_root.nlh) {
+        error("NFACCT: nfacct_nlmsg_build_hdr() failed");
+        return 1;
+    }
+
+    // send the request
+    if(mnl_socket_sendto(nfacct_root.mnl, nfacct_root.nlh, nfacct_root.nlh->nlmsg_len) < 0) {
+        error("NFACCT: mnl_socket_sendto() failed");
+        return 1;
+    }
+
+    // get the reply
+    ssize_t ret;
+    while((ret = mnl_socket_recvfrom(nfacct_root.mnl, nfacct_root.buf, nfacct_root.buf_size)) > 0) {
+        if(mnl_cb_run(
+                nfacct_root.buf
+                , (size_t)ret
+                , nfacct_root.seq
+                , nfacct_root.portid
+                , nfacct_callback
+                , NULL
+        ) <= 0)
+            break;
+    }
+
+    // verify we run without issues
+    if (ret == -1) {
+        error("NFACCT: error communicating with kernel. This plugin can only work when netdata runs as root.");
+        return 1;
+    }
+
+    return 0;
+}
+
+static void nfacct_send_metrics() {
+    static RRDSET *st_bytes = NULL, *st_packets = NULL;
+
+    if(!nfacct_root.nfacct_metrics) return;
+    struct nfacct_data *d;
+
+    if(!st_packets) {
+        st_packets = rrdset_create_localhost(
+                "netfilter"
+                , "nfacct_packets"
+                , NULL
+                , "nfacct"
+                , NULL
+                , "Netfilter Accounting Packets"
+                , "packets/s"
+                , 3206
+                , nfacct_root.update_every
+                , RRDSET_TYPE_STACKED
+        );
+    }
+    else rrdset_next(st_packets);
+
+    for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+        if(likely(d->updated)) {
+            if(unlikely(!d->rd_packets))
+                d->rd_packets = rrddim_add(
+                        st_packets
+                        , d->name
+                        , NULL
+                        , 1
+                        , nfacct_root.update_every
+                        , RRD_ALGORITHM_INCREMENTAL
+                );
+
+            rrddim_set_by_pointer(
+                    st_packets
+                    , d->rd_packets
+                    , (collected_number)d->pkts
+            );
         }
+    }
+
+    rrdset_done(st_packets);
+
+    // ----------------------------------------------------------------
+
+    st_bytes = rrdset_find_bytype_localhost("netfilter", "nfacct_bytes");
+    if(!st_bytes) {
+        st_bytes = rrdset_create_localhost(
+                "netfilter"
+                , "nfacct_bytes"
+                , NULL
+                , "nfacct"
+                , NULL
+                , "Netfilter Accounting Bandwidth"
+                , "kilobytes/s"
+                , 3207
+                , nfacct_root.update_every
+                , RRDSET_TYPE_STACKED
+        );
+    }
+    else rrdset_next(st_bytes);
+
+    for(d = nfacct_root.nfacct_metrics; d ; d = d->next) {
+        if(likely(d->updated)) {
+            if(unlikely(!d->rd_bytes))
+                d->rd_bytes = rrddim_add(
+                        st_bytes
+                        , d->name
+                        , NULL
+                        , 1
+                        , 1000 * nfacct_root.update_every
+                        , RRD_ALGORITHM_INCREMENTAL
+                );
+
+            rrddim_set_by_pointer(
+                    st_bytes
+                    , d->rd_bytes
+                    , (collected_number)d->bytes
+            );
+        }
+    }
+
+    rrdset_done(st_bytes);
+}
+
+#endif // HAVE_LIBNETFILTER_ACCT
+#endif // HAVE_LIBMNL
+
+// ----------------------------------------------------------------------------
+
+void *nfacct_main(void *ptr) {
+    struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
+
+    info("NETFILTER thread created with task id %d", gettid());
+
+    if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
+        error("NETFILTER: Cannot set pthread cancel type to DEFERRED.");
+
+    if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
+        error("NETFILTER: Cannot set pthread cancel state to ENABLE.");
 
-        // --------------------------------------------------------------------
 
-        usleep(susec);
+    int update_every = (int)config_get_number("plugin:netfilter", "update every", localhost->rrd_update_every);
+    if(update_every < localhost->rrd_update_every)
+        update_every = localhost->rrd_update_every;
 
-        // copy current to last
-        memmove(&last, &now, sizeof(struct timeval));
+#ifdef DO_NFACCT
+    int nfacct = !nfacct_init(update_every);
+#endif
+
+#ifdef DO_NFSTAT
+    int nfstat = !nfstat_init(update_every);
+#endif
+
+    // ------------------------------------------------------------------------
+
+    usec_t step = update_every * USEC_PER_SEC;
+    heartbeat_t hb;
+    heartbeat_init(&hb);
+    for(;;) {
+        heartbeat_dt_usec(&hb);
+        heartbeat_next(&hb, step);
+
+        if(unlikely(netdata_exit)) break;
+
+#ifdef DO_NFACCT
+        if(likely(nfacct)) {
+            nfacct = !nfacct_collect();
+
+            if(likely(nfacct))
+                nfacct_send_metrics();
+        }
+#endif
+
+#ifdef DO_NFSTAT
+        if(likely(nfstat)) {
+            nfstat = !nfstat_collect();
+
+            if(likely(nfstat))
+                nfstat_send_metrics();
+        }
+#endif
     }
 
-cleanup:
-    info("NFACCT thread exiting");
+    info("NETFILTER thread exiting");
 
-    if(nl) mnl_socket_close(nl);
+#ifdef DO_NFACCT
+    nfacct_cleanup();
+#endif
+
+#ifdef DO_NFSTAT
+    nfstat_cleanup();
+#endif
 
     static_thread->enabled = 0;
     pthread_exit(NULL);
     return NULL;
 }
-#endif
+
+#endif // INTERNAL_PLUGIN_NFACCT
index e0de84c70c070508ff6e9ee84da3f8664e070449..1b00758d5451b3c2c8d1cec3bdb9a6a980728e5d 100644 (file)
@@ -81,6 +81,7 @@ static void netdev_free(struct netdev *d) {
     if(d->st_compressed) rrdset_flag_set(d->st_compressed, RRDSET_FLAG_OBSOLETE);
     if(d->st_events)     rrdset_flag_set(d->st_events,     RRDSET_FLAG_OBSOLETE);
 
+    netdev_added--;
     freez(d->name);
     freez(d);
 }
@@ -88,6 +89,7 @@ static void netdev_free(struct netdev *d) {
 static void netdev_cleanup() {
     if(likely(netdev_found == netdev_added)) return;
 
+    netdev_added = 0;
     struct netdev *d = netdev_root, *last = NULL;
     while(d) {
         if(unlikely(!d->updated)) {
@@ -108,6 +110,7 @@ static void netdev_cleanup() {
             netdev_free(t);
         }
         else {
+            netdev_added++;
             last = d;
             d->updated = 0;
             d = d->next;
index 8c4581c1b57aa345287b720d2feb34d9a8ce4c48..aa9ab2209abbcdb02064dd264ae751750b89937b 100644 (file)
@@ -311,8 +311,8 @@ int do_proc_net_snmp6(int update_every, usec_t dt) {
 
         rrddim_set(st, "sent", Ip6OutRequests);
         rrddim_set(st, "received", Ip6InReceives);
-        rrddim_set(st, "forwarded", Ip6InDelivers);
-        rrddim_set(st, "delivers", Ip6OutForwDatagrams);
+        rrddim_set(st, "forwarded", Ip6OutForwDatagrams);
+        rrddim_set(st, "delivers", Ip6InDelivers);
         rrdset_done(st);
     }
 
index 81ff96f892415a82a80f6a2ff2f330203a8e9caa..a2310330d2ec0fdf27507a253039bfe333f38d69 100644 (file)
@@ -97,7 +97,7 @@ RRDHOST *rrdhost_create(const char *hostname,
 
     RRDHOST *host = callocz(1, sizeof(RRDHOST));
 
-    host->rrd_update_every    = update_every;
+    host->rrd_update_every    = (update_every > 0)?update_every:1;
     host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries);
     host->rrd_memory_mode     = memory_mode;
     host->health_enabled      = (memory_mode == RRD_MEMORY_MODE_NONE)? 0 : health_enabled;
index 16d057f4031b75977d0009da3a9bbf183926ca49..b15c6fc42677f4697731e599540584f63a88a19d 100644 (file)
@@ -147,10 +147,17 @@ void read_cgroup_plugin_configuration() {
 
     enabled_cgroup_patterns = simple_pattern_create(
             config_get("plugin:cgroups", "enable by default cgroups matching",
-                    " /system.slice/docker-*.scope "
+            // ----------------------------------------------------------------
+
+                    " !*/init.scope "                      // ignore init.scope
+                    " *.scope "                            // we need all *.scope for sure
+
+            // ----------------------------------------------------------------
+
+                    " !*/vcpu* "                           // libvirtd adds these sub-cgroups
+                    " !*/emulator "                        // libvirtd adds these sub-cgroups
                     " !*.mount "
                     " !*.partition "
-                    " !*.scope "
                     " !*.service "
                     " !*.slice "
                     " !*.swap "
@@ -159,18 +166,19 @@ void read_cgroup_plugin_configuration() {
                     " !/docker "
                     " !/libvirt "
                     " !/lxc "
-                    " !/lxc/*/ns "         //  #1397
+                    " !/lxc/*/ns "                         //  #1397
                     " !/machine "
                     " !/qemu "
                     " !/system "
                     " !/systemd "
                     " !/user "
-                    " * "                  // enable anything else
+                    " * "                                  // enable anything else
             ), SIMPLE_PATTERN_EXACT);
 
     enabled_cgroup_paths = simple_pattern_create(
             config_get("plugin:cgroups", "search for cgroups in subpaths matching",
-                    " !*-qemu "            //  #345
+                    " !*/init.scope "                      // ignore init.scope
+                    " !*-qemu "                            //  #345
                     " !/init.scope "
                     " !/system "
                     " !/systemd "
@@ -184,12 +192,13 @@ void read_cgroup_plugin_configuration() {
 
     enabled_cgroup_renames = simple_pattern_create(
             config_get("plugin:cgroups", "run script to rename cgroups matching",
+                    " *.scope "
                     " *docker* "
                     " *lxc* "
+                    " *qemu* "
                     " !/ "
                     " !*.mount "
                     " !*.partition "
-                    " !*.scope "
                     " !*.service "
                     " !*.slice "
                     " !*.swap "
index ef39d3b5834e92ff2444848816fca0e6db94f11b..b5b25899f624f30b97c3667ec4b53444e93c7cd8 100644 (file)
@@ -25,6 +25,8 @@ static inline int web_client_crock_socket(struct web_client *w) {
             return -1;
         }
     }
+#else
+    (void)w;
 #endif /* TCP_CORK */
 
     return 0;
@@ -40,6 +42,8 @@ static inline int web_client_uncrock_socket(struct web_client *w) {
             return -1;
         }
     }
+#else
+    (void)w;
 #endif /* TCP_CORK */
 
     return 0;
index e260e2738038e7396df07bcb601a26772e86d815..6bbb84eb5faa3229ea5a78db828b89b6d03bc386 100644 (file)
@@ -1,6 +1,6 @@
 [Unit]
 Description=Real time performance monitoring
-After=network.target httpd.service squid.service nfs-server.service mysqld.service named.service postfix.service
+After=network.target httpd.service squid.service nfs-server.service mysqld.service mysql.service named.service postfix.service
 
 [Service]
 Type=simple