--- /dev/null
+From: Nick Hainke <vincent@systemli.org>
+Date: Mon, 7 Dec 2020 19:29:54 +0100
+Subject: [PATCH] snmp6: add ipv6 statistics
+
+ChangeLog: snmp6 plugin: Add plugin for parsing IPv6 statistics
+
+We would like to have pure ipv6 interface statistics. To get them,
+we parse the snmp6 interface.
+
+Signed-off-by: Nick Hainke <vincent@systemli.org>
+---
+ Makefile.am | 8 +++
+ README | 4 ++
+ configure.ac | 2 +
+ src/collectd.conf.in | 6 ++
+ src/snmp6.c | 135 +++++++++++++++++++++++++++++++++++++++++++
+ src/types.db | 2 +
+ 6 files changed, 157 insertions(+)
+ create mode 100644 src/snmp6.c
+
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -1964,6 +1964,14 @@ TESTS += test_plugin_snmp_agent
+
+ endif
+
++if BUILD_PLUGIN_SNMP6
++pkglib_LTLIBRARIES += snmp6.la
++snmp6_la_SOURCES = src/snmp6.c
++snmp6_la_CFLAGS = $(AM_CFLAGS)
++snmp6_la_LDFLAGS = $(PLUGIN_LDFLAGS)
++snmp6_la_LIBADD = libignorelist.la
++endif # BUILD_PLUGIN_SNMP6
++
+ if BUILD_PLUGIN_STATSD
+ pkglib_LTLIBRARIES += statsd.la
+ statsd_la_SOURCES = src/statsd.c
+--- a/README
++++ b/README
+@@ -422,6 +422,10 @@ Features
+ network devices such as switches, routers, thermometers, rack monitoring
+ servers, etc. See collectd-snmp(5).
+
++ - snmp6
++ Read values from SNMP6 (Simple Network Management Protocol). Supports pure
++ IPv6 interface statistics.
++
+ - statsd
+ Acts as a StatsD server, reading values sent over the network from StatsD
+ clients and calculating rates and other aggregates out of these values.
+--- a/configure.ac
++++ b/configure.ac
+@@ -7162,6 +7162,7 @@ AC_PLUGIN([slurm], [$with_
+ AC_PLUGIN([smart], [$plugin_smart], [SMART statistics])
+ AC_PLUGIN([snmp], [$with_libnetsnmp], [SNMP querying plugin])
+ AC_PLUGIN([snmp_agent], [$with_libnetsnmpagent], [SNMP agent plugin])
++AC_PLUGIN([snmp6], [yes], [IPv6 Interface traffic statistics via snmp6])
+ AC_PLUGIN([statsd], [yes], [StatsD plugin])
+ AC_PLUGIN([swap], [$plugin_swap], [Swap usage statistics])
+ AC_PLUGIN([synproxy], [$plugin_synproxy], [Synproxy stats plugin])
+@@ -7611,6 +7612,7 @@ AC_MSG_RESULT([ slurm . . . . . . . .
+ AC_MSG_RESULT([ smart . . . . . . . . $enable_smart])
+ AC_MSG_RESULT([ snmp . . . . . . . . $enable_snmp])
+ AC_MSG_RESULT([ snmp_agent . . . . . $enable_snmp_agent])
++AC_MSG_RESULT([ snmp6 . . . . . . . . $enable_snmp6])
+ AC_MSG_RESULT([ statsd . . . . . . . $enable_statsd])
+ AC_MSG_RESULT([ swap . . . . . . . . $enable_swap])
+ AC_MSG_RESULT([ synproxy . . . . . . $enable_synproxy])
+--- a/src/collectd.conf.in
++++ b/src/collectd.conf.in
+@@ -207,6 +207,7 @@
+ #@BUILD_PLUGIN_SMART_TRUE@LoadPlugin smart
+ #@BUILD_PLUGIN_SNMP_TRUE@LoadPlugin snmp
+ #@BUILD_PLUGIN_SNMP_AGENT_TRUE@LoadPlugin snmp_agent
++#@BUILD_PLUGIN_SNMP6_TRUE@LoadPlugin snmp6
+ #@BUILD_PLUGIN_STATSD_TRUE@LoadPlugin statsd
+ #@BUILD_PLUGIN_SWAP_TRUE@LoadPlugin swap
+ #@BUILD_PLUGIN_SYSEVENT_TRUE@LoadPlugin sysevent
+@@ -1718,6 +1719,11 @@
+ # </Table>
+ #</Plugin>
+
++#<Plugin snmp6>
++# Interface "eth0"
++# IgnoreSelected false
++#</Plugin>
++
+ #<Plugin statsd>
+ # Host "::"
+ # Port "8125"
+--- /dev/null
++++ b/src/snmp6.c
+@@ -0,0 +1,135 @@
++/*
++ This Plugin is based opn the interface.c Plugin.
++*/
++
++#if HAVE_LINUX_IF_H
++#include <linux/if.h>
++#elif HAVE_NET_IF_H
++#include <net/if.h>
++#endif
++
++#include <ifaddrs.h>
++
++#include <stdint.h>
++#include <stdlib.h>
++#include <string.h>
++
++#include <errno.h>
++#include <stdbool.h>
++#include <stdio.h>
++#include <sys/types.h>
++
++#include "plugin.h"
++#include "utils/cmds/putval.h"
++#include "utils/common/common.h"
++#include "utils/ignorelist/ignorelist.h"
++
++static const char *config_keys[] = {
++ "Interface",
++ "IgnoreSelected",
++};
++static int config_keys_num = STATIC_ARRAY_SIZE(config_keys);
++
++static ignorelist_t *ignorelist;
++struct ifaddrs *if_list;
++
++static int snmp6_config(const char *key, const char *value) {
++ if (ignorelist == NULL)
++ ignorelist = ignorelist_create(/* invert = */ 1);
++
++ if (strcasecmp(key, "Interface") == 0) {
++ ignorelist_add(ignorelist, value);
++ } else if (strcasecmp(key, "IgnoreSelected") == 0) {
++ int invert = 1;
++ if (IS_TRUE(value))
++ invert = 0;
++ ignorelist_set_invert(ignorelist, invert);
++ }
++
++ return 0;
++}
++
++/* Copied from interface.c */
++static void snmp6_submit(const char *dev, const char *type, derive_t rx,
++ derive_t tx) {
++ value_list_t vl = VALUE_LIST_INIT;
++ value_t values[] = {
++ {.derive = rx},
++ {.derive = tx},
++ };
++
++ if (ignorelist_match(ignorelist, dev) != 0)
++ return;
++
++ vl.values = values;
++ vl.values_len = STATIC_ARRAY_SIZE(values);
++ sstrncpy(vl.plugin, "snmp6", sizeof(vl.plugin));
++ sstrncpy(vl.plugin_instance, dev, sizeof(vl.plugin_instance));
++ sstrncpy(vl.type, type, sizeof(vl.type));
++
++ plugin_dispatch_values(&vl);
++} /* void if_submit */
++
++int snmp_read(char *ifname) {
++ FILE *fh;
++ char buffer[1024];
++ char *fields[16];
++ int numfields;
++ int currline = 0;
++ derive_t data[76];
++ char procpath[1024];
++ int offset = 0;
++
++ if (strncmp("all", ifname, strlen("all")) == 0) {
++ snprintf(procpath, 1024, "/proc/net/snmp6");
++ offset = 1;
++ } else {
++ snprintf(procpath, 1024, "/proc/net/dev_snmp6/%s", ifname);
++ }
++
++ if ((fh = fopen(procpath, "r")) == NULL) {
++ WARNING("interface plugin: fopen: %s", STRERRNO);
++ return -1;
++ }
++
++ while (fgets(buffer, 1024, fh) != NULL) {
++ numfields = strsplit(buffer, fields, 16);
++
++ if (numfields < 2)
++ continue;
++
++ data[currline++] = atoll(fields[1]);
++ }
++
++ fclose(fh);
++
++ if (currline < 25) {
++ return -1;
++ }
++
++ snmp6_submit(ifname, "if_octets", data[23 - offset], data[24 - offset]);
++ snmp6_submit(ifname, "if_octets_mcast", data[25 - offset], data[26 - offset]);
++ snmp6_submit(ifname, "if_octets_bcast", data[27 - offset], data[28 - offset]);
++ return 0;
++}
++
++int read_all_interfaces(void) {
++#ifndef HAVE_IFADDRS_H
++ return -1;
++#else
++ if (getifaddrs(&if_list) != 0)
++ return -1;
++
++ for (struct ifaddrs *if_ptr = if_list; if_ptr != NULL;
++ if_ptr = if_ptr->ifa_next) {
++ snmp_read(if_ptr->ifa_name);
++ }
++ snmp_read("all");
++ return 0;
++#endif
++}
++
++void module_register(void) {
++ plugin_register_config("snmp6", snmp6_config, config_keys, config_keys_num);
++ plugin_register_read("snmp6", read_all_interfaces);
++} /* void module_register */
+--- a/src/types.db
++++ b/src/types.db
+@@ -132,6 +132,8 @@ if_dropped rx:DERIVE:0:U, t
+ if_errors rx:DERIVE:0:U, tx:DERIVE:0:U
+ if_multicast value:DERIVE:0:U
+ if_octets rx:DERIVE:0:U, tx:DERIVE:0:U
++if_octets_mcast rx:DERIVE:0:U, tx:DERIVE:0:U
++if_octets_bcast rx:DERIVE:0:U, tx:DERIVE:0:U
+ if_packets rx:DERIVE:0:U, tx:DERIVE:0:U
+ if_rx_dropped value:DERIVE:0:U
+ if_rx_errors value:DERIVE:0:U