Merge pull request #2097 from YmrDtnJu/zfs_arc
authorRuben Kerkhof <ruben@rubenkerkhof.com>
Sat, 31 Dec 2016 12:47:04 +0000 (13:47 +0100)
committerGitHub <noreply@github.com>
Sat, 31 Dec 2016 12:47:04 +0000 (13:47 +0100)
zfs_arc updates for linux

35 files changed:
.gitignore
ChangeLog
Makefile.am
README
bindings/Makefile.am [deleted file]
bindings/java/Makefile.am [deleted file]
configure.ac
contrib/redhat/collectd.spec
m4/.gitignore [new file with mode: 0644]
proto/Makefile.am [deleted file]
src/Makefile.am [deleted file]
src/battery.c
src/collectd.conf.in
src/collectd.conf.pod
src/daemon/Makefile.am [deleted file]
src/daemon/common.c
src/daemon/configfile.c
src/daemon/utils_random.c
src/daemon/utils_random.h
src/dpdkstat.c
src/email.c
src/libcollectdclient/Makefile.am [deleted file]
src/liboconfig/Makefile.am [deleted file]
src/mcelog.c [new file with mode: 0644]
src/netapp.c
src/netlink.c
src/ovs_events.c [new file with mode: 0644]
src/target_set.c
src/utils_cmd_getthreshold.c
src/utils_ovs.c [new file with mode: 0644]
src/utils_ovs.h [new file with mode: 0644]
src/virt.c
src/write_prometheus.c
src/write_tsdb.c
version-gen.sh

index 6927e51..2911069 100644 (file)
@@ -37,12 +37,13 @@ src/stamp-h1
 *.la
 *.lo
 *.o
+.dirstamp
 .libs/
 .deps/
-src/collectd-nagios
-src/collectd-tg
-src/collectdctl
-src/collectdmon
+/collectd-nagios
+/collectd-tg
+/collectdctl
+/collectdmon
 src/*.1
 src/*.5
 src/.pod2man.tmp.*
@@ -59,26 +60,28 @@ src/liboconfig/parser.h
 src/liboconfig/scanner.c
 
 # protobuf stuff:
-src/*.pb-c.[ch]
-src/*.grpc.pb.cc
-src/*.pb.cc
-src/*.pb.h
+*.pb-c.[ch]
+*.grpc.pb.cc
+*.pb.cc
+*.pb.h
 
 # make dist stuff:
 /collectd-*.tar.gz
 /collectd-*.tar.bz2
 
 # perl stuff:
-bindings/.perl-directory-stamp
+/.perl-directory-stamp
 bindings/perl/Collectd/pm_to_blib
 bindings/perl/blib/
 bindings/perl/pm_to_blib
-bindings/buildperl
+/buildperl
 
 # java stuff
-bindings/java/java-build-stamp
-bindings/java/org/collectd/api/*.class
-bindings/java/org/collectd/java/*.class
+*.jar
+/org/collectd/api/*.class
+/org/collectd/java/*.class
+/bindings/java/java-build-stamp
+/classnoinst.stamp
 
 # python stuff
 *.pyc
@@ -102,4 +105,4 @@ src/test-suite.log
 test_*
 
 # src/daemon/...
-src/daemon/collectd
+/collectd
index e42b231..db0b062 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,73 @@
+2016-12-12, Version 5.7.0
+       * Documentation: The Turbostat plugin section has been improved. Thanks
+         to Florian Forster
+       * Documentation: The semantics of the "TypesDB" option have been
+         improved. Thanks to Florian Forster.
+       * collectd: A generic interface for parsing the text protocol has been
+         added. Thanks to Sebastian Harl. #1749
+       * collectd: Threads now get named, making them easier to track using
+         tools such as top, ps, etc. Thanks to Manuel Luis SanmartĂ­n Rozada
+         and Marc Fournier. #547
+       * AMQP plugin, Write Graphite plugin, Write Kafka plugin: The new
+         "[Graphite]PreserveSeparator" option allows retaining the default dot
+         separator rather than escaping it. Thanks to Florian Forster. #419
+       * Battery plugin: A StateFS backend for gathering statistics has been
+         added. Thanks to Rinigus. #1795
+       * CPU plugin: CPU aggregation on AIX was fixed. Thanks to Chao Yang.
+         #1957
+       * Collectd::Unixsock: Fractional seconds support has been made more
+         robust. Thanks to Matthias Bethke. #2052
+       * DPDKStat plugin: This new plugin collects DPDK interface statistics.
+         Thanks to Maryam Tahhan, Harry van Haaren, Taras Chornyi and Kim
+         Jones. #1649
+       * gRPC plugin: The "DispatchValues" option has been renamed to
+         "PutValues". Thanks to Florian Forster.
+       * HDDTemp plugin: The 32 devices limit has been removed. Thanks to
+         Benjamin Gilbert. #631
+       * Hugepages plugin: This new plugin reports the number of used and free
+         hugepages on Linux. Thanks to Jaroslav Safka, Maryam Tahhan, Kim Jones
+         and Florian Forster. #1799
+       * Intel RDT plugin: This new plugin collects statistics exposed by
+         Intel's Resource Director Technology . Thanks to SerhiyX. #1970
+       * memcached plugin: The new "Address" option allows connecting to a
+         different server than specified by the "Host" option. Thanks to Pavel
+         Rochnyack. #1975
+       * nginx plugin: Support for reporting failed connections has been added.
+         Thanks to Pavel Rochnyack. #1609
+       * Perl plugin: Significant internal reworking has been made. The new
+         "RegisterLegacyFlush" option has been added. Thanks to Pavel
+         Rochnyack. #1731
+       * PostgreSQL plugin: Timestamps are now RFC 3339-formatted local time.
+         Thanks to Igor Peshansky and Dave Cunningham. #1918
+       * Processes plugin: Internal performance improvements have been made.
+         Thanks to Pavel Rochnyack. #1980, #1981
+       * RRDCacheD plugin: The plugin now tries to reconnect upon failed
+         operations. Thanks to Sebastian Harl. #1959
+       * SpamAssassin: The plugin can now run in Perl's "tainted mode" ("-T").
+         Thanks to Akos Vandra. #1962
+       * Tail plugin: Support for calculating latency distribution of matching
+         values has been added. Thanks to Pavel Rochnyack and Florian Forster.
+         #1700
+       * Tail plugin: The new "GaugePersist" option has been added. Thanks to
+         Florian Forster. #2015
+       * Target:Set, Target:Replace, Match:RegEx: MetaData support has been
+         added . Thanks to Igor Peshansky. #1922, #1923, #1930
+       * turbostat plugin: The new "LogicalCoreNames" option allows switching
+         to per-core naming rather than per-CPU. Thanks to Brock Johnson. #2056
+       * virt plugin: The new "BlockDeviceFormat" and
+         "BlockDeviceFormatBasename" options help controlling the names
+         reported for block-device metrics. Thanks to Deyan Chepishev. #2004
+       * Write Graphite plugin: A new "DropDuplicateFields" option has been
+         added. Thanks to Michael Leinartas. #1915
+       * Write Kafka plugin: The "Key Random" setting has been reintroduced.
+         Thanks to Florian Forster. #1977
+       * Write Log plugin: Support for formatting output in JSON has been
+         added, using the new "Format" configuration option. Thanks to Igor
+         Peshansky. #1924
+       * Write Prometheus plugin: This new plugin publishes values using an
+         embedded HTTP server, in a format compatible with Prometheus'
+         collectd_exporter. Thanks to Florian Forster. #1967
+
 2016-11-30, Version 5.6.2
        * collectd: A compile error on AIX has been fixed: "MSG_DONTWAIT" is not
          available on AIX. Thanks to Chao Yang.
index 83b0d64..90a3273 100644 (file)
 ACLOCAL_AMFLAGS = -I m4
+AM_YFLAGS = -d
 
-SUBDIRS = proto src bindings .
 
-EXTRA_DIST = contrib version-gen.sh testwrapper.sh
+BUILT_SOURCES = \
+       src/libcollectdclient/collectd/lcc_features.h \
+       src/liboconfig/parser.h \
+       $(dist_man_MANS)
+
+
+CLEANFILES = \
+       .perl-directory-stamp \
+       bindings/buildperl/Collectd.pm \
+       bindings/buildperl/Collectd/Plugins/OpenVZ.pm \
+       bindings/buildperl/Collectd/Unixsock.pm \
+       bindings/buildperl/Makefile.PL \
+       collectd-api.jar \
+       collectd.grpc.pb.cc \
+       collectd.grpc.pb.h \
+       collectd.pb.cc \
+       collectd.pb.h \
+       generic-jmx.jar \
+       org/collectd/api/*.class \
+       org/collectd/java/*.class \
+       prometheus.pb-c.c \
+       prometheus.pb-c.h \
+       src/pinba.pb-c.c \
+       src/pinba.pb-c.h \
+       types.pb.cc \
+       types.pb.h
+
+
+EXTRA_DIST = \
+       bindings/perl/Makefile.PL \
+       bindings/perl/lib/Collectd.pm \
+       bindings/perl/lib/Collectd/Plugins/Monitorus.pm \
+       bindings/perl/lib/Collectd/Plugins/OpenVZ.pm \
+       bindings/perl/lib/Collectd/Unixsock.pm \
+       bindings/perl/uninstall_mod.pl \
+       contrib \
+       proto/collectd.proto \
+       proto/prometheus.proto \
+       proto/types.proto \
+       src/collectd-email.pod \
+       src/collectd-exec.pod \
+       src/collectd-java.pod \
+       src/collectd-lua.pod \
+       src/collectd-nagios.pod \
+       src/collectd-perl.pod \
+       src/collectd-python.pod \
+       src/collectd-snmp.pod \
+       src/collectd-tg.pod \
+       src/collectd-threshold.pod \
+       src/collectd-unixsock.pod \
+       src/collectd.conf.pod \
+       src/collectd.pod \
+       src/collectdctl.pod \
+       src/collectdmon.pod \
+       src/pinba.proto \
+       src/postgresql_default.conf \
+       src/types.db \
+       src/types.db.pod \
+       src/valgrind.FreeBSD.suppress \
+       testwrapper.sh \
+       version-gen.sh
+
+
+dist_man_MANS = \
+       src/collectd.1 \
+       src/collectd.conf.5 \
+       src/collectd-email.5 \
+       src/collectd-exec.5 \
+       src/collectdctl.1 \
+       src/collectd-java.5 \
+       src/collectd-lua.5 \
+       src/collectdmon.1 \
+       src/collectd-nagios.1 \
+       src/collectd-perl.5 \
+       src/collectd-python.5 \
+       src/collectd-snmp.5 \
+       src/collectd-tg.1 \
+       src/collectd-threshold.5 \
+       src/collectd-unixsock.5 \
+       src/types.db.5
+
+
+nodist_pkgconfig_DATA = \
+       src/libcollectdclient/libcollectdclient.pc
+
+pkginclude_HEADERS = \
+       src/libcollectdclient/collectd/client.h \
+       src/libcollectdclient/collectd/network.h \
+       src/libcollectdclient/collectd/network_buffer.h \
+       src/libcollectdclient/collectd/lcc_features.h
+
+lib_LTLIBRARIES = libcollectdclient.la
+
+
+sbin_PROGRAMS = \
+       collectd \
+       collectdmon
+
+
+bin_PROGRAMS = \
+       collectd-nagios \
+       collectd-tg \
+       collectdctl
+
+
+noinst_LTLIBRARIES = \
+       libavltree.la \
+       libcmds.la \
+       libcommon.la \
+       libformat_graphite.la \
+       libformat_json.la \
+       libheap.la \
+       liblatency.la \
+       liblookup.la \
+       libmetadata.la \
+       libmount.la \
+       liboconfig.la \
+       libplugin_mock.la
+
+
+check_PROGRAMS = \
+       test_common \
+       test_format_graphite \
+       test_meta_data \
+       test_utils_avltree \
+       test_utils_cmds \
+       test_utils_heap \
+       test_utils_latency \
+       test_utils_mount \
+       test_utils_subst \
+       test_utils_time \
+       test_utils_vl_lookup
+
+
+TESTS = $(check_PROGRAMS)
+
+LOG_COMPILER = env VALGRIND="@VALGRIND@" $(abs_srcdir)/testwrapper.sh
+
+
+jardir = $(pkgdatadir)/java
+
+pkglib_LTLIBRARIES =
+
+
+PLUGIN_LDFLAGS = \
+       -module \
+       -avoid-version \
+       -export-symbols-regex '\<module_register\>'
+
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/src -I$(top_srcdir)/src/daemon \
+       -DPREFIX='"${prefix}"' \
+       -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"' \
+       -DLOCALSTATEDIR='"${localstatedir}"' \
+       -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"' \
+       -DPLUGINDIR='"${pkglibdir}"' \
+       -DPKGDATADIR='"${pkgdatadir}"'
+
+
+# Link to these libraries..
+COMMON_LIBS = $(PTHREAD_LIBS)
+if BUILD_WITH_CAPABILITY
+COMMON_LIBS += -lcap
+endif
+if BUILD_WITH_LIBRT
+COMMON_LIBS += -lrt
+endif
+if BUILD_WITH_LIBPOSIX4
+COMMON_LIBS += -lposix4
+endif
+if BUILD_WITH_LIBSOCKET
+COMMON_LIBS += -lsocket
+endif
+if BUILD_WITH_LIBKSTAT
+COMMON_LIBS += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+COMMON_LIBS += -ldevinfo
+endif
+
+
+collectd_SOURCES = \
+       src/daemon/collectd.c \
+       src/daemon/collectd.h \
+       src/daemon/configfile.c \
+       src/daemon/configfile.h \
+       src/daemon/filter_chain.c \
+       src/daemon/filter_chain.h \
+       src/daemon/meta_data.c \
+       src/daemon/meta_data.h \
+       src/daemon/plugin.c \
+       src/daemon/plugin.h \
+       src/daemon/utils_cache.c \
+       src/daemon/utils_cache.h \
+       src/daemon/utils_complain.c \
+       src/daemon/utils_complain.h \
+       src/daemon/utils_ignorelist.c \
+       src/daemon/utils_ignorelist.h \
+       src/daemon/utils_llist.c \
+       src/daemon/utils_llist.h \
+       src/daemon/utils_random.c \
+       src/daemon/utils_random.h \
+       src/daemon/utils_subst.c \
+       src/daemon/utils_subst.h \
+       src/daemon/utils_time.c \
+       src/daemon/utils_time.h \
+       src/daemon/types_list.c \
+       src/daemon/types_list.h \
+       src/daemon/utils_threshold.c \
+       src/daemon/utils_threshold.h
+
+
+collectd_CFLAGS = $(AM_CFLAGS)
+collectd_CPPFLAGS = $(AM_CPPFLAGS)
+collectd_LDFLAGS = -export-dynamic
+collectd_LDADD = \
+       libavltree.la \
+       libcommon.la \
+       libheap.la \
+       liboconfig.la \
+       -lm \
+       $(COMMON_LIBS) \
+       $(DLOPEN_LIBS)
+
+if BUILD_FEATURE_DAEMON
+collectd_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
+endif
+
+# The daemon needs to call sg_init, so we need to link it against libstatgrab,
+# too. -octo
+if BUILD_WITH_LIBSTATGRAB
+collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+
+
+collectdmon_SOURCES = src/collectdmon.c
+
+
+collectd_nagios_SOURCES = src/collectd-nagios.c
+collectd_nagios_CPPFLAGS = $(AM_CPPFLAGS) \
+       -I$(srcdir)/src/libcollectdclient/collectd \
+       -I$(top_builddir)/src/libcollectdclient/collectd
+collectd_nagios_LDADD = libcollectdclient.la
+if BUILD_WITH_LIBSOCKET
+collectd_nagios_LDADD += -lsocket
+endif
+if BUILD_AIX
+collectd_nagios_LDADD += -lm
+endif
+
+
+collectdctl_SOURCES = src/collectdctl.c
+collectdctl_CPPFLAGS = $(AM_CPPFLAGS) \
+       -I$(srcdir)/src/libcollectdclient/collectd \
+       -I$(top_builddir)/src/libcollectdclient/collectd
+collectdctl_LDADD = libcollectdclient.la
+if BUILD_WITH_LIBSOCKET
+collectdctl_LDADD += -lsocket
+endif
+if BUILD_AIX
+collectdctl_LDADD += -lm
+endif
+
+
+collectd_tg_SOURCES = src/collectd-tg.c
+collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) \
+       -I$(srcdir)/src/libcollectdclient/collectd \
+       -I$(top_builddir)/src/libcollectdclient/collectd
+collectd_tg_LDADD = \
+       $(PTHREAD_LIBS) \
+       libheap.la \
+       libcollectdclient.la
+if BUILD_WITH_LIBSOCKET
+collectd_tg_LDADD += -lsocket
+endif
+if BUILD_WITH_LIBRT
+collectd_tg_LDADD += -lrt
+endif
+if BUILD_AIX
+collectd_tg_LDADD += -lm
+endif
+
+
+test_common_SOURCES = \
+       src/daemon/common_test.c \
+       src/testing.h
+test_common_LDADD = libplugin_mock.la
+
+test_meta_data_SOURCES = \
+       src/daemon/meta_data_test.c \
+       src/testing.h
+test_meta_data_LDADD = libmetadata.la libplugin_mock.la
+
+test_utils_avltree_SOURCES = \
+       src/daemon/utils_avltree_test.c \
+       src/testing.h
+test_utils_avltree_LDADD = libavltree.la $(COMMON_LIBS)
+
+test_utils_heap_SOURCES = \
+       src/daemon/utils_heap_test.c \
+       src/testing.h
+test_utils_heap_LDADD = libheap.la $(COMMON_LIBS)
+
+test_utils_time_SOURCES = \
+       src/daemon/utils_time_test.c \
+       src/testing.h
+
+test_utils_subst_SOURCES = \
+       src/daemon/utils_subst_test.c \
+       src/testing.h \
+       src/daemon/utils_subst.c \
+       src/daemon/utils_subst.h
+test_utils_subst_LDADD = libplugin_mock.la
+
+libavltree_la_SOURCES = \
+       src/daemon/utils_avltree.c \
+       src/daemon/utils_avltree.h
+
+libcommon_la_SOURCES = \
+       src/daemon/common.c \
+       src/daemon/common.h
+libcommon_la_LIBADD = $(COMMON_LIBS)
+
+libheap_la_SOURCES = \
+       src/daemon/utils_heap.c \
+       src/daemon/utils_heap.h
+
+libmetadata_la_SOURCES = \
+       src/daemon/meta_data.c \
+       src/daemon/meta_data.h
+
+libplugin_mock_la_SOURCES = \
+       src/daemon/plugin_mock.c \
+       src/daemon/utils_cache_mock.c \
+       src/daemon/utils_complain.c \
+       src/daemon/utils_complain.h \
+       src/daemon/utils_ignorelist.c \
+       src/daemon/utils_ignorelist.h \
+       src/daemon/utils_time.c \
+       src/daemon/utils_time.h
+
+libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME
+libplugin_mock_la_LIBADD = libcommon.la $(COMMON_LIBS)
+
+libformat_graphite_la_SOURCES = \
+       src/utils_format_graphite.c \
+       src/utils_format_graphite.h
+
+test_format_graphite_SOURCES = \
+       src/utils_format_graphite_test.c \
+       src/testing.h
+test_format_graphite_LDADD = \
+       libformat_graphite.la \
+       libmetadata.la \
+       libplugin_mock.la \
+       -lm
+
+libformat_json_la_SOURCES = \
+       src/utils_format_json.c \
+       src/utils_format_json.h
+libformat_json_la_CPPFLAGS  = $(AM_CPPFLAGS)
+libformat_json_la_LDFLAGS   = $(AM_LDFLAGS)
+libformat_json_la_LIBADD    =
+if BUILD_WITH_LIBYAJL
+libformat_json_la_CPPFLAGS += $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+libformat_json_la_LDFLAGS  += $(BUILD_WITH_LIBYAJL_LDFLAGS)
+libformat_json_la_LIBADD   += $(BUILD_WITH_LIBYAJL_LIBS)
+
+check_PROGRAMS += test_format_json
+
+test_format_json_SOURCES = \
+       src/utils_format_json_test.c \
+       src/testing.h
+test_format_json_LDADD = \
+       libformat_json.la \
+       libmetadata.la \
+       libplugin_mock.la \
+       -lm
+endif
+
+if BUILD_PLUGIN_CEPH
+test_plugin_ceph_SOURCES = src/ceph_test.c
+test_plugin_ceph_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+test_plugin_ceph_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+test_plugin_ceph_LDADD = libplugin_mock.la $(BUILD_WITH_LIBYAJL_LIBS)
+check_PROGRAMS += test_plugin_ceph
+endif
+
+liblatency_la_SOURCES = \
+       src/utils_latency.c \
+       src/utils_latency.h \
+       src/utils_latency_config.c \
+       src/utils_latency_config.h
+liblatency_la_LIBADD = \
+       libcommon.la \
+       -lm
+
+test_utils_latency_SOURCES = \
+       src/utils_latency_test.c \
+       src/testing.h
+test_utils_latency_LDADD = \
+       liblatency.la \
+       libplugin_mock.la \
+       -lm
+
+libcmds_la_SOURCES = \
+       src/utils_cmds.c \
+       src/utils_cmds.h \
+       src/utils_cmd_flush.c \
+       src/utils_cmd_flush.h \
+       src/utils_cmd_getthreshold.c \
+       src/utils_cmd_getthreshold.h \
+       src/utils_cmd_getval.c \
+       src/utils_cmd_getval.h \
+       src/utils_cmd_listval.c \
+       src/utils_cmd_listval.h \
+       src/utils_cmd_putnotif.c \
+       src/utils_cmd_putnotif.h \
+       src/utils_cmd_putval.c \
+       src/utils_cmd_putval.h \
+       src/utils_parse_option.c \
+       src/utils_parse_option.h
+libcmds_la_LIBADD = \
+       libcommon.la \
+       libmetadata.la \
+       -lm
+
+test_utils_cmds_SOURCES = \
+       src/utils_cmds_test.c \
+       src/testing.h
+test_utils_cmds_LDADD = \
+       libcmds.la \
+       libplugin_mock.la
+
+liblookup_la_SOURCES = \
+       src/utils_vl_lookup.c \
+       src/utils_vl_lookup.h
+liblookup_la_LIBADD = libavltree.la
+
+test_utils_vl_lookup_SOURCES = \
+       src/utils_vl_lookup_test.c \
+       src/testing.h
+test_utils_vl_lookup_LDADD = \
+       liblookup.la \
+       libplugin_mock.la
+if BUILD_WITH_LIBKSTAT
+test_utils_vl_lookup_LDADD += -lkstat
+endif
+
+libmount_la_SOURCES = \
+       src/utils_mount.c \
+       src/utils_mount.h
+
+test_utils_mount_SOURCES = \
+       src/utils_mount_test.c \
+       src/testing.h
+test_utils_mount_LDADD = \
+       libmount.la \
+       libplugin_mock.la
+if BUILD_WITH_LIBKSTAT
+test_utils_mount_LDADD += -lkstat
+endif
+
+
+libcollectdclient_la_SOURCES = \
+       src/libcollectdclient/client.c \
+       src/libcollectdclient/network.c \
+       src/libcollectdclient/network_buffer.c
+libcollectdclient_la_CPPFLAGS = \
+       $(AM_CPPFLAGS) \
+       -I$(srcdir)/src/libcollectdclient/collectd \
+       -I$(top_builddir)/src/libcollectdclient/collectd \
+       -I$(srcdir)/src/daemon
+libcollectdclient_la_LDFLAGS = -version-info 1:0:0
+libcollectdclient_la_LIBADD = 
+if BUILD_WITH_LIBGCRYPT
+libcollectdclient_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
+libcollectdclient_la_LDFLAGS += $(GCRYPT_LDFLAGS)
+libcollectdclient_la_LIBADD += $(GCRYPT_LIBS)
+endif
+
+
+liboconfig_la_SOURCES = \
+       src/liboconfig/oconfig.c \
+       src/liboconfig/oconfig.h \
+       src/liboconfig/aux_types.h \
+       src/liboconfig/scanner.l \
+       src/liboconfig/parser.y
+liboconfig_la_LDFLAGS = -avoid-version $(LEXLIB)
+
+
+if BUILD_PLUGIN_AGGREGATION
+pkglib_LTLIBRARIES += aggregation.la
+aggregation_la_SOURCES = \
+       src/aggregation.c \
+       src/utils_vl_lookup.c \
+       src/utils_vl_lookup.h
+aggregation_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+aggregation_la_LIBADD = -lm
+endif
+
+if BUILD_PLUGIN_AMQP
+pkglib_LTLIBRARIES += amqp.la
+amqp_la_SOURCES = src/amqp.c
+amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
+amqp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
+amqp_la_LIBADD = \
+       $(BUILD_WITH_LIBRABBITMQ_LIBS) \
+       libcmds.la \
+       libformat_graphite.la \
+       libformat_json.la
+endif
+
+if BUILD_PLUGIN_APACHE
+pkglib_LTLIBRARIES += apache.la
+apache_la_SOURCES = src/apache.c
+apache_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
+apache_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+apache_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
+endif
+
+
+if BUILD_PLUGIN_APCUPS
+pkglib_LTLIBRARIES += apcups.la
+apcups_la_SOURCES = src/apcups.c
+apcups_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+apcups_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+apcups_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_APPLE_SENSORS
+pkglib_LTLIBRARIES += apple_sensors.la
+apple_sensors_la_SOURCES = src/apple_sensors.c
+apple_sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) -framework IOKit
+endif
+
+if BUILD_PLUGIN_AQUAERO
+pkglib_LTLIBRARIES += aquaero.la
+aquaero_la_SOURCES = src/aquaero.c
+aquaero_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBAQUAERO5_CFLAGS)
+aquaero_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBAQUAERO5_LDFLAGS)
+aquaero_la_LIBADD = -laquaero5
+endif
+
+if BUILD_PLUGIN_ASCENT
+pkglib_LTLIBRARIES += ascent.la
+ascent_la_SOURCES = src/ascent.c
+ascent_la_CFLAGS = \
+       $(AM_CFLAGS) \
+       $(BUILD_WITH_LIBCURL_CFLAGS) \
+       $(BUILD_WITH_LIBXML2_CFLAGS)
+ascent_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+ascent_la_LIBADD = \
+       $(BUILD_WITH_LIBCURL_LIBS) \
+       $(BUILD_WITH_LIBXML2_LIBS)
+endif
+
+if BUILD_PLUGIN_BAROMETER
+pkglib_LTLIBRARIES += barometer.la
+barometer_la_SOURCES = src/barometer.c
+barometer_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+barometer_la_LIBADD = -lm
+endif
+
+if BUILD_PLUGIN_BATTERY
+pkglib_LTLIBRARIES += battery.la
+battery_la_SOURCES = \
+       src/battery.c \
+       src/battery_statefs.c
+battery_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+if BUILD_WITH_LIBIOKIT
+battery_la_LDFLAGS += -framework IOKit
+endif
+endif
+
+if BUILD_PLUGIN_BIND
+pkglib_LTLIBRARIES += bind.la
+bind_la_SOURCES = src/bind.c
+bind_la_CFLAGS = $(AM_CFLAGS) \
+                $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+bind_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+bind_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
+endif
+
+if BUILD_PLUGIN_CEPH
+pkglib_LTLIBRARIES += ceph.la
+ceph_la_SOURCES = src/ceph.c
+ceph_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+ceph_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+ceph_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
+endif
+
+if BUILD_PLUGIN_CGROUPS
+pkglib_LTLIBRARIES += cgroups.la
+cgroups_la_SOURCES = src/cgroups.c
+cgroups_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+cgroups_la_LIBADD = libmount.la
+endif
+
+if BUILD_PLUGIN_CHRONY
+pkglib_LTLIBRARIES += chrony.la
+chrony_la_SOURCES = src/chrony.c
+chrony_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CONNTRACK
+pkglib_LTLIBRARIES += conntrack.la
+conntrack_la_SOURCES = src/conntrack.c
+conntrack_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CONTEXTSWITCH
+pkglib_LTLIBRARIES += contextswitch.la
+contextswitch_la_SOURCES = src/contextswitch.c
+contextswitch_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+contextswitch_la_LIBADD =
+if BUILD_WITH_PERFSTAT
+contextswitch_la_LIBADD += -lperfstat
+endif
+endif
+
+if BUILD_PLUGIN_CPU
+pkglib_LTLIBRARIES += cpu.la
+cpu_la_SOURCES = src/cpu.c
+cpu_la_CFLAGS = $(AM_CFLAGS)
+cpu_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+cpu_la_LIBADD =
+if BUILD_WITH_LIBKSTAT
+cpu_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+cpu_la_LIBADD += -ldevinfo
+endif
+if BUILD_WITH_LIBSTATGRAB
+cpu_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+cpu_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+if BUILD_WITH_PERFSTAT
+cpu_la_LIBADD += -lperfstat
+endif
+endif
+
+if BUILD_PLUGIN_CPUFREQ
+pkglib_LTLIBRARIES += cpufreq.la
+cpufreq_la_SOURCES = src/cpufreq.c
+cpufreq_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CPUSLEEP
+pkglib_LTLIBRARIES += cpusleep.la
+cpusleep_la_SOURCES = src/cpusleep.c
+cpusleep_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CSV
+pkglib_LTLIBRARIES += csv.la
+csv_la_SOURCES = src/csv.c
+csv_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_CURL
+pkglib_LTLIBRARIES += curl.la
+curl_la_SOURCES = \
+       src/curl.c \
+       src/utils_curl_stats.c \
+       src/utils_curl_stats.h \
+       src/utils_match.c \
+       src/utils_match.h
+curl_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
+curl_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+curl_la_LIBADD = liblatency.la $(BUILD_WITH_LIBCURL_LIBS)
+endif
+
+if BUILD_PLUGIN_CURL_JSON
+pkglib_LTLIBRARIES += curl_json.la
+curl_json_la_SOURCES = \
+       src/curl_json.c \
+       src/utils_curl_stats.c \
+       src/utils_curl_stats.h
+curl_json_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
+curl_json_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+curl_json_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+curl_json_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBYAJL_LIBS)
+endif
+
+if BUILD_PLUGIN_CURL_XML
+pkglib_LTLIBRARIES += curl_xml.la
+curl_xml_la_SOURCES = \
+       src/curl_xml.c \
+       src/utils_curl_stats.c \
+       src/utils_curl_stats.h
+curl_xml_la_CFLAGS = $(AM_CFLAGS) \
+               $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+curl_xml_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+curl_xml_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
+endif
+
+if BUILD_PLUGIN_DBI
+pkglib_LTLIBRARIES += dbi.la
+dbi_la_SOURCES = \
+       src/dbi.c \
+       src/utils_db_query.c \
+       src/utils_db_query.h
+dbi_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBDBI_CPPFLAGS)
+dbi_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBDBI_LDFLAGS)
+dbi_la_LIBADD = $(BUILD_WITH_LIBDBI_LIBS)
+endif
+
+if BUILD_PLUGIN_DF
+pkglib_LTLIBRARIES += df.la
+df_la_SOURCES = src/df.c
+df_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+df_la_LIBADD = libmount.la
+endif
+
+if BUILD_PLUGIN_DISK
+pkglib_LTLIBRARIES += disk.la
+disk_la_SOURCES = src/disk.c
+disk_la_CFLAGS = $(AM_CFLAGS)
+disk_la_CPPFLAGS = $(AM_CPPFLAGS)
+disk_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+disk_la_LIBADD =
+if BUILD_WITH_LIBKSTAT
+disk_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+disk_la_LIBADD += -ldevinfo
+endif
+if BUILD_WITH_LIBIOKIT
+disk_la_LDFLAGS += -framework IOKit
+endif
+if BUILD_WITH_LIBSTATGRAB
+disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+disk_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+if BUILD_WITH_LIBUDEV
+disk_la_CPPFLAGS += $(BUILD_WITH_LIBUDEV_CPPFLAGS)
+disk_la_LDFLAGS += $(BUILD_WITH_LIBUDEV_LDFLAGS)
+disk_la_LIBADD += $(BUILD_WITH_LIBUDEV_LIBS)
+endif
+if BUILD_FREEBSD
+disk_la_LIBADD += -ldevstat -lgeom
+endif
+if BUILD_WITH_PERFSTAT
+disk_la_LIBADD += -lperfstat
+endif
+endif
+
+if BUILD_PLUGIN_DNS
+pkglib_LTLIBRARIES += dns.la
+dns_la_SOURCES = \
+       src/dns.c \
+       src/utils_dns.c \
+       src/utils_dns.h
+dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPCAP_CPPFLAGS)
+dns_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPCAP_LDFLAGS)
+dns_la_LIBADD = $(BUILD_WITH_LIBPCAP_LIBS)
+endif
+
+if BUILD_PLUGIN_DPDKSTAT
+pkglib_LTLIBRARIES += dpdkstat.la
+dpdkstat_la_SOURCES = src/dpdkstat.c
+dpdkstat_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS)
+dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS)
+dpdkstat_la_LIBADD = -ldpdk
+endif
+
+if BUILD_PLUGIN_DRBD
+pkglib_LTLIBRARIES += drbd.la
+drbd_la_SOURCES = src/drbd.c
+drbd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_EMAIL
+pkglib_LTLIBRARIES += email.la
+email_la_SOURCES = src/email.c
+email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_ENTROPY
+pkglib_LTLIBRARIES += entropy.la
+entropy_la_SOURCES = src/entropy.c
+entropy_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_EXEC
+pkglib_LTLIBRARIES += exec.la
+exec_la_SOURCES = src/exec.c
+exec_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+exec_la_LIBADD = libcmds.la
+endif
+
+if BUILD_PLUGIN_ETHSTAT
+pkglib_LTLIBRARIES += ethstat.la
+ethstat_la_SOURCES = src/ethstat.c
+ethstat_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_FHCOUNT
+pkglib_LTLIBRARIES += fhcount.la
+fhcount_la_SOURCES = src/fhcount.c
+fhcount_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_FILECOUNT
+pkglib_LTLIBRARIES += filecount.la
+filecount_la_SOURCES = src/filecount.c
+filecount_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_GMOND
+pkglib_LTLIBRARIES += gmond.la
+gmond_la_SOURCES = src/gmond.c
+gmond_la_CPPFLAGS = $(AM_CPPFLAGS) $(GANGLIA_CPPFLAGS)
+gmond_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(GANGLIA_LDFLAGS)
+gmond_la_LIBADD = $(GANGLIA_LIBS)
+endif
+
+if BUILD_PLUGIN_GPS
+pkglib_LTLIBRARIES += gps.la
+gps_la_SOURCES = src/gps.c
+gps_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBGPS_CFLAGS)
+gps_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBGPS_LDFLAGS)
+gps_la_LIBADD = -lpthread $(BUILD_WITH_LIBGPS_LIBS)
+endif
+
+if BUILD_PLUGIN_GRPC
+pkglib_LTLIBRARIES += grpc.la
+grpc_la_SOURCES = src/grpc.cc
+nodist_grpc_la_SOURCES = \
+       collectd.grpc.pb.cc \
+       collectd.pb.cc \
+       types.pb.cc
+grpc_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBGRPCPP_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_CPPFLAGS)
+grpc_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBGRPCPP_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_LDFLAGS)
+grpc_la_LIBADD = $(BUILD_WITH_LIBGRPCPP_LIBS) $(BUILD_WITH_LIBPROTOBUF_LIBS)
+endif
+
+if BUILD_PLUGIN_HDDTEMP
+pkglib_LTLIBRARIES += hddtemp.la
+hddtemp_la_SOURCES = src/hddtemp.c
+hddtemp_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+hddtemp_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+hddtemp_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_HUGEPAGES
+pkglib_LTLIBRARIES += hugepages.la
+hugepages_la_SOURCES = src/hugepages.c
+hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_INTEL_RDT
+pkglib_LTLIBRARIES += intel_rdt.la
+intel_rdt_la_SOURCES = src/intel_rdt.c
+intel_rdt_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBPQOS_CPPFLAGS)
+intel_rdt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPQOS_LDFLAGS)
+intel_rdt_la_LIBADD = $(BUILD_WITH_LIBPQOS_LIBS)
+endif
+
+if BUILD_PLUGIN_INTERFACE
+pkglib_LTLIBRARIES += interface.la
+interface_la_SOURCES = src/interface.c
+interface_la_CFLAGS = $(AM_CFLAGS)
+interface_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+interface_la_LIBADD =
+if BUILD_WITH_LIBSTATGRAB
+interface_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+interface_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+else
+if BUILD_WITH_LIBKSTAT
+interface_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+interface_la_LIBADD += -ldevinfo
+endif # BUILD_WITH_LIBDEVINFO
+endif # !BUILD_WITH_LIBSTATGRAB
+if BUILD_WITH_PERFSTAT
+interface_la_LIBADD += -lperfstat
+endif
+endif # BUILD_PLUGIN_INTERFACE
+
+if BUILD_PLUGIN_IPC
+pkglib_LTLIBRARIES += ipc.la
+ipc_la_SOURCES = src/ipc.c
+ipc_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_IPTABLES
+pkglib_LTLIBRARIES += iptables.la
+iptables_la_SOURCES = src/iptables.c
+iptables_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBIPTC_CPPFLAGS)
+iptables_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+iptables_la_LIBADD = $(BUILD_WITH_LIBIPTC_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_IPMI
+pkglib_LTLIBRARIES += ipmi.la
+ipmi_la_SOURCES = src/ipmi.c
+ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
+ipmi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
+endif
+
+if BUILD_PLUGIN_IPVS
+pkglib_LTLIBRARIES += ipvs.la
+ipvs_la_SOURCES = src/ipvs.c
+ipvs_la_CFLAGS = $(AM_CFLAGS)
+if IP_VS_H_NEEDS_KERNEL_CFLAGS
+ipvs_la_CFLAGS += $(KERNEL_CFLAGS)
+endif
+ipvs_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_IRQ
+pkglib_LTLIBRARIES += irq.la
+irq_la_SOURCES = src/irq.c
+irq_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_JAVA
+pkglib_LTLIBRARIES += java.la
+java_la_SOURCES = src/java.c
+java_la_CPPFLAGS = $(AM_CPPFLAGS) $(JAVA_CPPFLAGS)
+java_la_CFLAGS = $(AM_CFLAGS) $(JAVA_CFLAGS)
+java_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(JAVA_LDFLAGS)
+java_la_LIBADD = $(JAVA_LIBS)
+endif
+
+if BUILD_PLUGIN_LOAD
+pkglib_LTLIBRARIES += load.la
+load_la_SOURCES = src/load.c
+load_la_CFLAGS = $(AM_CFLAGS)
+load_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+load_la_LIBADD =
+if BUILD_WITH_LIBSTATGRAB
+load_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+load_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif # BUILD_WITH_LIBSTATGRAB
+if BUILD_WITH_PERFSTAT
+load_la_LIBADD += -lperfstat
+endif
+endif # BUILD_PLUGIN_LOAD
+
+if BUILD_PLUGIN_LOGFILE
+pkglib_LTLIBRARIES += logfile.la
+logfile_la_SOURCES = src/logfile.c
+logfile_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_LOG_LOGSTASH
+pkglib_LTLIBRARIES += log_logstash.la
+log_logstash_la_SOURCES = src/log_logstash.c
+log_logstash_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+log_logstash_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+log_logstash_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
+endif
+
+if BUILD_PLUGIN_LPAR
+pkglib_LTLIBRARIES += lpar.la
+lpar_la_SOURCES = src/lpar.c
+lpar_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+lpar_la_LIBADD = -lperfstat
+endif
+
+if BUILD_PLUGIN_LUA
+pkglib_LTLIBRARIES += lua.la
+lua_la_SOURCES = \
+       src/lua.c \
+       src/utils_lua.c \
+       src/utils_lua.h
+lua_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBLUA_CFLAGS)
+lua_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+lua_la_LIBADD = $(BUILD_WITH_LIBLUA_LIBS)
+endif
+
+if BUILD_PLUGIN_LVM
+pkglib_LTLIBRARIES += lvm.la
+lvm_la_SOURCES = src/lvm.c
+lvm_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLVM2APP_CPPFLAGS)
+lvm_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLVM2APP_LDFLAGS)
+lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
+endif
+
+if BUILD_PLUGIN_MADWIFI
+pkglib_LTLIBRARIES += madwifi.la
+madwifi_la_SOURCES = \
+       src/madwifi.c \
+       src/madwifi.h
+madwifi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MATCH_EMPTY_COUNTER
+pkglib_LTLIBRARIES += match_empty_counter.la
+match_empty_counter_la_SOURCES = src/match_empty_counter.c
+match_empty_counter_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MATCH_HASHED
+pkglib_LTLIBRARIES += match_hashed.la
+match_hashed_la_SOURCES = src/match_hashed.c
+match_hashed_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MATCH_REGEX
+pkglib_LTLIBRARIES += match_regex.la
+match_regex_la_SOURCES = src/match_regex.c
+match_regex_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MATCH_TIMEDIFF
+pkglib_LTLIBRARIES += match_timediff.la
+match_timediff_la_SOURCES = src/match_timediff.c
+match_timediff_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MATCH_VALUE
+pkglib_LTLIBRARIES += match_value.la
+match_value_la_SOURCES = src/match_value.c
+match_value_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MBMON
+pkglib_LTLIBRARIES += mbmon.la
+mbmon_la_SOURCES = src/mbmon.c
+mbmon_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+mbmon_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+mbmon_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_MCELOG
+pkglib_LTLIBRARIES += mcelog.la
+mcelog_la_SOURCES = src/mcelog.c
+mcelog_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MD
+pkglib_LTLIBRARIES += md.la
+md_la_SOURCES = src/md.c
+md_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MEMCACHEC
+pkglib_LTLIBRARIES += memcachec.la
+memcachec_la_SOURCES = \
+       src/memcachec.c \
+       src/utils_match.c \
+       src/utils_match.h
+memcachec_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
+memcachec_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMEMCACHED_LDFLAGS)
+memcachec_la_LIBADD = liblatency.la $(BUILD_WITH_LIBMEMCACHED_LIBS)
+endif
+
+if BUILD_PLUGIN_MEMCACHED
+pkglib_LTLIBRARIES += memcached.la
+memcached_la_SOURCES = src/memcached.c
+memcached_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+memcached_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+memcached_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_MEMORY
+pkglib_LTLIBRARIES += memory.la
+memory_la_SOURCES = src/memory.c
+memory_la_CFLAGS = $(AM_CFLAGS)
+memory_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+memory_la_LIBADD =
+if BUILD_WITH_LIBKSTAT
+memory_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+memory_la_LIBADD += -ldevinfo
+endif
+if BUILD_WITH_LIBSTATGRAB
+memory_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+memory_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+if BUILD_WITH_PERFSTAT
+memory_la_LIBADD += -lperfstat
+endif
+endif
+
+if BUILD_PLUGIN_MIC
+pkglib_LTLIBRARIES += mic.la
+mic_la_SOURCES = src/mic.c
+mic_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
+mic_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_MIC_LDFLAGS)
+mic_la_LIBADD = $(BUILD_WITH_MIC_LIBS)
+endif
+
+if BUILD_PLUGIN_MODBUS
+pkglib_LTLIBRARIES += modbus.la
+modbus_la_SOURCES = src/modbus.c
+modbus_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMODBUS_CFLAGS)
+modbus_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+modbus_la_LIBADD = $(BUILD_WITH_LIBMODBUS_LIBS)
+endif
+
+if BUILD_PLUGIN_MQTT
+pkglib_LTLIBRARIES += mqtt.la
+mqtt_la_SOURCES = src/mqtt.c
+mqtt_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
+mqtt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMOSQUITTO_LDFLAGS)
+mqtt_la_LIBADD = $(BUILD_WITH_LIBMOSQUITTO_LIBS)
+endif
+
+if BUILD_PLUGIN_MULTIMETER
+pkglib_LTLIBRARIES += multimeter.la
+multimeter_la_SOURCES = src/multimeter.c
+multimeter_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_MYSQL
+pkglib_LTLIBRARIES += mysql.la
+mysql_la_SOURCES = src/mysql.c
+mysql_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMYSQL_CFLAGS)
+mysql_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+mysql_la_LIBADD = $(BUILD_WITH_LIBMYSQL_LIBS)
+endif
+
+if BUILD_PLUGIN_NETAPP
+pkglib_LTLIBRARIES += netapp.la
+netapp_la_SOURCES = src/netapp.c
+netapp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBNETAPP_CPPFLAGS)
+netapp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBNETAPP_LDFLAGS)
+netapp_la_LIBADD = $(LIBNETAPP_LIBS)
+endif
+
+if BUILD_PLUGIN_NETLINK
+pkglib_LTLIBRARIES += netlink.la
+netlink_la_SOURCES = src/netlink.c
+netlink_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMNL_CFLAGS)
+netlink_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+netlink_la_LIBADD = $(BUILD_WITH_LIBMNL_LIBS)
+endif
+
+if BUILD_PLUGIN_NETWORK
+pkglib_LTLIBRARIES += network.la
+network_la_SOURCES = \
+       src/network.c \
+       src/network.h \
+       src/utils_fbhash.c \
+       src/utils_fbhash.h
+network_la_CPPFLAGS = $(AM_CPPFLAGS)
+network_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+network_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+network_la_LIBADD += -lsocket
+endif
+if BUILD_WITH_LIBGCRYPT
+network_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
+network_la_LDFLAGS += $(GCRYPT_LDFLAGS)
+network_la_LIBADD += $(GCRYPT_LIBS)
+endif
+endif
+
+if BUILD_PLUGIN_NFS
+pkglib_LTLIBRARIES += nfs.la
+nfs_la_SOURCES = src/nfs.c
+nfs_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_FSCACHE
+pkglib_LTLIBRARIES += fscache.la
+fscache_la_SOURCES = src/fscache.c
+fscache_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_NGINX
+pkglib_LTLIBRARIES += nginx.la
+nginx_la_SOURCES = src/nginx.c
+nginx_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
+nginx_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+nginx_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
+endif
+
+if BUILD_PLUGIN_NOTIFY_DESKTOP
+pkglib_LTLIBRARIES += notify_desktop.la
+notify_desktop_la_SOURCES = src/notify_desktop.c
+notify_desktop_la_CFLAGS = $(AM_CFLAGS) $(LIBNOTIFY_CFLAGS)
+notify_desktop_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+notify_desktop_la_LIBADD = $(LIBNOTIFY_LIBS)
+endif
+
+if BUILD_PLUGIN_NOTIFY_EMAIL
+pkglib_LTLIBRARIES += notify_email.la
+notify_email_la_SOURCES = src/notify_email.c
+notify_email_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBESMTP_CPPFLAGS)
+notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBESMTP_LDFLAGS)
+notify_email_la_LIBADD = $(BUILD_WITH_LIBESMTP_LIBS)
+endif
+
+if BUILD_PLUGIN_NOTIFY_NAGIOS
+pkglib_LTLIBRARIES += notify_nagios.la
+notify_nagios_la_SOURCES = src/notify_nagios.c
+notify_nagios_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_NTPD
+pkglib_LTLIBRARIES += ntpd.la
+ntpd_la_SOURCES = src/ntpd.c
+ntpd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+ntpd_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+ntpd_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_NUMA
+pkglib_LTLIBRARIES += numa.la
+numa_la_SOURCES = src/numa.c
+numa_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_NUT
+pkglib_LTLIBRARIES += nut.la
+nut_la_SOURCES = src/nut.c
+nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
+nut_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+nut_la_LIBADD = $(BUILD_WITH_LIBUPSCLIENT_LIBS)
+endif
+
+if BUILD_PLUGIN_OLSRD
+pkglib_LTLIBRARIES += olsrd.la
+olsrd_la_SOURCES = src/olsrd.c
+olsrd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+olsrd_la_LIBADD =
+if BUILD_WITH_LIBSOCKET
+olsrd_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_ONEWIRE
+pkglib_LTLIBRARIES += onewire.la
+onewire_la_SOURCES = src/onewire.c
+onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
+onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
+onewire_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOWCAPI_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_OPENLDAP
+pkglib_LTLIBRARIES += openldap.la
+openldap_la_SOURCES = src/openldap.c
+openldap_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLDAP_CPPFLAGS)
+openldap_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLDAP_LDFLAGS)
+openldap_la_LIBADD = -lldap
+endif
+
+if BUILD_PLUGIN_OPENVPN
+pkglib_LTLIBRARIES += openvpn.la
+openvpn_la_SOURCES = src/openvpn.c
+openvpn_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_ORACLE
+pkglib_LTLIBRARIES += oracle.la
+oracle_la_SOURCES = \
+       src/oracle.c \
+       src/utils_db_query.c \
+       src/utils_db_query.h
+oracle_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_ORACLE_CPPFLAGS)
+oracle_la_LIBADD = $(BUILD_WITH_ORACLE_LIBS)
+oracle_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_OVS_EVENTS
+pkglib_LTLIBRARIES += ovs_events.la
+ovs_events_la_SOURCES = \
+       src/ovs_events.c \
+       src/utils_ovs.c \
+       src/utils_ovs.h
+ovs_events_la_CPPFLAGS = $(BUILD_WITH_LIBYAJL_CPPFLAGS)
+ovs_events_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
+ovs_events_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
+endif
+
+if BUILD_PLUGIN_PERL
+pkglib_LTLIBRARIES += perl.la
+perl_la_SOURCES = src/perl.c
+# Despite C99 providing the "bool" type thru stdbool.h, Perl defines its own
+# version of that type if HAS_BOOL is not defined... *sigh*
+perl_la_CPPFLAGS = $(AM_CPPFLAGS) -DHAS_BOOL=1
+# Despite off_t being 64 bit wide on 64 bit platforms, Perl insist on using
+# off64_t which is only exposed when _LARGEFILE64_SOURCE is defined... *sigh*
+# On older platforms we also need _REENTRANT. _GNU_SOURCE sets both of these.
+perl_la_CPPFLAGS += -D_GNU_SOURCE
+perl_la_CFLAGS  = $(AM_CFLAGS) \
+               $(PERL_CFLAGS) \
+               -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
+perl_la_LDFLAGS = $(PLUGIN_LDFLAGS) \
+               $(PERL_LDFLAGS)
+perl_la_LIBADD = $(PERL_LIBS)
+endif
+
+if BUILD_PLUGIN_PF
+pkglib_LTLIBRARIES += pf.la
+pf_la_SOURCES = src/pf.c
+pf_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_PINBA
+pkglib_LTLIBRARIES += pinba.la
+pinba_la_SOURCES = src/pinba.c
+nodist_pinba_la_SOURCES = \
+       src/pinba.pb-c.c \
+       src/pinba.pb-c.h
+pinba_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_CPPFLAGS)
+pinba_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_LDFLAGS)
+pinba_la_LIBADD = $(BUILD_WITH_LIBPROTOBUF_C_LIBS)
+endif
+
+if BUILD_PLUGIN_PING
+pkglib_LTLIBRARIES += ping.la
+ping_la_SOURCES = src/ping.c
+ping_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOPING_CPPFLAGS)
+ping_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOPING_LDFLAGS)
+ping_la_LIBADD = -loping -lm
+endif
+
+if BUILD_PLUGIN_POSTGRESQL
+pkglib_LTLIBRARIES += postgresql.la
+postgresql_la_SOURCES = \
+       src/postgresql.c \
+       src/utils_db_query.c \
+       src/utils_db_query.h
+postgresql_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPQ_CPPFLAGS)
+postgresql_la_LDFLAGS = $(PLUGIN_LDFLAGS) \
+               $(BUILD_WITH_LIBPQ_LDFLAGS)
+postgresql_la_LIBADD = $(BUILD_WITH_LIBPQ_LIBS)
+endif
+
+if BUILD_PLUGIN_POWERDNS
+pkglib_LTLIBRARIES += powerdns.la
+powerdns_la_SOURCES = src/powerdns.c
+powerdns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_PYTHON
+pkglib_LTLIBRARIES += python.la
+python_la_SOURCES = \
+       src/python.c \
+       src/pyconfig.c \
+       src/pyvalues.c \
+       src/cpython.h
+python_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBPYTHON_CPPFLAGS)
+if COMPILER_IS_GCC
+python_la_CPPFLAGS += -fno-strict-aliasing -Wno-strict-aliasing
+endif
+python_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBPYTHON_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_PROCESSES
+pkglib_LTLIBRARIES += processes.la
+processes_la_SOURCES = src/processes.c
+processes_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+processes_la_LIBADD =
+if BUILD_WITH_LIBKVM_GETPROCS
+processes_la_LIBADD += -lkvm
+endif
+endif
+
+if BUILD_PLUGIN_PROTOCOLS
+pkglib_LTLIBRARIES += protocols.la
+protocols_la_SOURCES = src/protocols.c
+protocols_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_REDIS
+pkglib_LTLIBRARIES += redis.la
+redis_la_SOURCES = src/redis.c
+redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBHIREDIS_CPPFLAGS)
+redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBHIREDIS_LDFLAGS)
+redis_la_LIBADD = -lhiredis
+endif
+
+if BUILD_PLUGIN_ROUTEROS
+pkglib_LTLIBRARIES += routeros.la
+routeros_la_SOURCES = src/routeros.c
+routeros_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
+routeros_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBROUTEROS_LDFLAGS)
+routeros_la_LIBADD = -lrouteros
+endif
+
+if BUILD_PLUGIN_RRDCACHED
+pkglib_LTLIBRARIES += rrdcached.la
+rrdcached_la_SOURCES = \
+       src/rrdcached.c \
+       src/utils_rrdcreate.c \
+       src/utils_rrdcreate.h
+rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdcached_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRRD_LDFLAGS)
+rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LIBS)
+endif
+
+if BUILD_PLUGIN_RRDTOOL
+pkglib_LTLIBRARIES += rrdtool.la
+rrdtool_la_SOURCES = \
+       src/rrdtool.c \
+       src/utils_rrdcreate.c \
+       src/utils_rrdcreate.h
+rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
+rrdtool_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRRD_LDFLAGS)
+rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LIBS)
+endif
+
+if BUILD_PLUGIN_SENSORS
+pkglib_LTLIBRARIES += sensors.la
+sensors_la_SOURCES = src/sensors.c
+sensors_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBSENSORS_CPPFLAGS)
+sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBSENSORS_LDFLAGS)
+sensors_la_LIBADD = $(BUILD_WITH_LIBSENSORS_LIBS)
+endif
+
+if BUILD_PLUGIN_SERIAL
+pkglib_LTLIBRARIES += serial.la
+serial_la_SOURCES = src/serial.c
+serial_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_SIGROK
+pkglib_LTLIBRARIES += sigrok.la
+sigrok_la_SOURCES = src/sigrok.c
+sigrok_la_CFLAGS = $(AM_CFLAGS) $(LIBSIGROK_CFLAGS)
+sigrok_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+sigrok_la_LIBADD = $(LIBSIGROK_LIBS)
+endif
+
+if BUILD_PLUGIN_SMART
+if BUILD_WITH_LIBUDEV
+pkglib_LTLIBRARIES += smart.la
+smart_la_SOURCES = src/smart.c
+smart_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBATASMART_CPPFLAGS) $(BUILD_WITH_LIBUDEV_CPPFLAGS)
+smart_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBATASMART_LDFLAGS) $(BUILD_WITH_LIBUDEV_LDFLAGS)
+smart_la_LIBADD = $(BUILD_WITH_LIBATASMART_LIBS) $(BUILD_WITH_LIBUDEV_LIBS)
+endif
+endif
+
+if BUILD_PLUGIN_SNMP
+pkglib_LTLIBRARIES += snmp.la
+snmp_la_SOURCES = src/snmp.c
+snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
+snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
+snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
+endif
+
+if BUILD_PLUGIN_STATSD
+pkglib_LTLIBRARIES += statsd.la
+statsd_la_SOURCES = src/statsd.c
+statsd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+statsd_la_LIBADD = liblatency.la
+endif
+
+if BUILD_PLUGIN_SWAP
+pkglib_LTLIBRARIES += swap.la
+swap_la_SOURCES = src/swap.c
+swap_la_CFLAGS = $(AM_CFLAGS)
+swap_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+swap_la_LIBADD =
+if BUILD_WITH_LIBKSTAT
+swap_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_LIBDEVINFO
+swap_la_LIBADD += -ldevinfo
+endif
+if BUILD_WITH_LIBKVM_GETSWAPINFO
+swap_la_LIBADD += -lkvm
+endif
+if BUILD_WITH_LIBSTATGRAB
+swap_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+swap_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+if BUILD_WITH_PERFSTAT
+swap_la_LIBADD += -lperfstat
+endif
+
+endif
+
+if BUILD_PLUGIN_SYSLOG
+pkglib_LTLIBRARIES += syslog.la
+syslog_la_SOURCES = src/syslog.c
+syslog_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TABLE
+pkglib_LTLIBRARIES += table.la
+table_la_SOURCES = src/table.c
+table_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TAIL
+pkglib_LTLIBRARIES += tail.la
+tail_la_SOURCES = \
+       src/tail.c \
+       src/utils_match.c \
+       src/utils_match.h \
+       src/utils_tail.c \
+       src/utils_tail.h \
+       src/utils_tail_match.c \
+       src/utils_tail_match.h
+tail_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+tail_la_LIBADD = liblatency.la
+endif
+
+if BUILD_PLUGIN_TAIL_CSV
+pkglib_LTLIBRARIES += tail_csv.la
+tail_csv_la_SOURCES = \
+       src/tail_csv.c \
+       src/utils_tail.c \
+       src/utils_tail.h
+tail_csv_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TAPE
+pkglib_LTLIBRARIES += tape.la
+tape_la_SOURCES = src/tape.c
+tape_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+tape_la_LIBADD = -lkstat -ldevinfo
+endif
+
+if BUILD_PLUGIN_TARGET_NOTIFICATION
+pkglib_LTLIBRARIES += target_notification.la
+target_notification_la_SOURCES = src/target_notification.c
+target_notification_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TARGET_REPLACE
+pkglib_LTLIBRARIES += target_replace.la
+target_replace_la_SOURCES = src/target_replace.c
+target_replace_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TARGET_SCALE
+pkglib_LTLIBRARIES += target_scale.la
+target_scale_la_SOURCES = src/target_scale.c
+target_scale_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TARGET_SET
+pkglib_LTLIBRARIES += target_set.la
+target_set_la_SOURCES = src/target_set.c
+target_set_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TARGET_V5UPGRADE
+pkglib_LTLIBRARIES += target_v5upgrade.la
+target_v5upgrade_la_SOURCES = src/target_v5upgrade.c
+target_v5upgrade_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TCPCONNS
+pkglib_LTLIBRARIES += tcpconns.la
+tcpconns_la_SOURCES = src/tcpconns.c
+tcpconns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+tcpconns_la_LIBADD =
+if BUILD_WITH_LIBKVM_NLIST
+tcpconns_la_LIBADD += -lkvm
+endif
+endif
+
+if BUILD_PLUGIN_TEAMSPEAK2
+pkglib_LTLIBRARIES += teamspeak2.la
+teamspeak2_la_SOURCES = src/teamspeak2.c
+teamspeak2_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TED
+pkglib_LTLIBRARIES += ted.la
+ted_la_SOURCES = src/ted.c
+ted_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_THERMAL
+pkglib_LTLIBRARIES += thermal.la
+thermal_la_SOURCES = src/thermal.c
+thermal_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_THRESHOLD
+pkglib_LTLIBRARIES += threshold.la
+threshold_la_SOURCES = src/threshold.c
+threshold_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_TOKYOTYRANT
+pkglib_LTLIBRARIES += tokyotyrant.la
+tokyotyrant_la_SOURCES = src/tokyotyrant.c
+tokyotyrant_la_CPPFLAGS  = $(AM_CPPFLAGS) $(BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS)
+tokyotyrant_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS)
+tokyotyrant_la_LIBADD  = $(BUILD_WITH_LIBTOKYOTYRANT_LIBS)
+if BUILD_WITH_LIBSOCKET
+tokyotyrant_la_LIBADD += -lsocket
+endif
+endif
+
+if BUILD_PLUGIN_TURBOSTAT
+pkglib_LTLIBRARIES += turbostat.la
+turbostat_la_SOURCES = src/turbostat.c
+turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_UNIXSOCK
+pkglib_LTLIBRARIES += unixsock.la
+unixsock_la_SOURCES = src/unixsock.c
+unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+unixsock_la_LIBS = libcmds.la
+endif
+
+if BUILD_PLUGIN_UPTIME
+pkglib_LTLIBRARIES += uptime.la
+uptime_la_SOURCES = src/uptime.c
+uptime_la_CFLAGS = $(AM_CFLAGS)
+uptime_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+uptime_la_LIBADD =
+if BUILD_WITH_LIBKSTAT
+uptime_la_LIBADD += -lkstat
+endif
+if BUILD_WITH_PERFSTAT
+uptime_la_LIBADD += -lperfstat
+endif
+endif
+
+if BUILD_PLUGIN_USERS
+pkglib_LTLIBRARIES += users.la
+users_la_SOURCES = src/users.c
+users_la_CFLAGS = $(AM_CFLAGS)
+users_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+users_la_LIBADD =
+if BUILD_WITH_LIBSTATGRAB
+users_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
+users_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
+endif
+endif
+
+if BUILD_PLUGIN_UUID
+pkglib_LTLIBRARIES += uuid.la
+uuid_la_SOURCES = src/uuid.c
+uuid_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_VARNISH
+pkglib_LTLIBRARIES += varnish.la
+varnish_la_SOURCES = src/varnish.c
+varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
+varnish_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
+endif
+
+if BUILD_PLUGIN_VIRT
+pkglib_LTLIBRARIES += virt.la
+virt_la_SOURCES = src/virt.c
+virt_la_CFLAGS = $(AM_CFLAGS) \
+               $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+virt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
+virt_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+
+# TODO: enable once we support only modern libvirts which depends on libnl-3
+# the libvirt on wheezy is linked in libnl v1, and there is a small leak here,
+# triggered by the library initialization. There are no means to avoid it,
+# and libvirt switched to libnl3 anyway
+#test_plugin_virt_SOURCES = src/virt_test.c
+#test_plugin_virt_CPPFLAGS = $(AM_CPPFLAGS) \
+#              $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
+#test_plugin_virt_LDFLAGS = $(PLUGIN_LDFLAGS)
+#test_plugin_virt_LDADD = libplugin_mock.la \
+#              $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
+#check_PROGRAMS += test_plugin_virt
+#TESTS += test_plugin_virt
+endif
+
+if BUILD_PLUGIN_VMEM
+pkglib_LTLIBRARIES += vmem.la
+vmem_la_SOURCES = src/vmem.c
+vmem_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_VSERVER
+pkglib_LTLIBRARIES += vserver.la
+vserver_la_SOURCES = src/vserver.c
+vserver_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_WIRELESS
+pkglib_LTLIBRARIES += wireless.la
+wireless_la_SOURCES = src/wireless.c
+wireless_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_WRITE_GRAPHITE
+pkglib_LTLIBRARIES += write_graphite.la
+write_graphite_la_SOURCES = src/write_graphite.c
+write_graphite_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+write_graphite_la_LIBADD = libformat_graphite.la
+endif
+
+if BUILD_PLUGIN_WRITE_HTTP
+pkglib_LTLIBRARIES += write_http.la
+write_http_la_SOURCES = \
+       src/write_http.c \
+       src/utils_format_kairosdb.c \
+       src/utils_format_kairosdb.h
+write_http_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
+write_http_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+write_http_la_LIBADD = libformat_json.la $(BUILD_WITH_LIBCURL_LIBS)
+endif
+
+if BUILD_PLUGIN_WRITE_KAFKA
+pkglib_LTLIBRARIES += write_kafka.la
+write_kafka_la_SOURCES = src/write_kafka.c
+write_kafka_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRDKAFKA_CPPFLAGS)
+write_kafka_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
+write_kafka_la_LIBADD = \
+       libcmds.la \
+       libformat_graphite.la \
+       libformat_json.la \
+       $(BUILD_WITH_LIBRDKAFKA_LIBS)
+endif
+
+if BUILD_PLUGIN_WRITE_LOG
+pkglib_LTLIBRARIES += write_log.la
+write_log_la_SOURCES = src/write_log.c
+write_log_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+write_log_la_LIBADD = libformat_graphite.la libformat_json.la
+endif
+
+if BUILD_PLUGIN_WRITE_MONGODB
+pkglib_LTLIBRARIES += write_mongodb.la
+write_mongodb_la_SOURCES = src/write_mongodb.c
+write_mongodb_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMONGOC_CPPFLAGS)
+write_mongodb_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMONGOC_LDFLAGS)
+write_mongodb_la_LIBADD = -lmongoc
+endif
+
+if BUILD_PLUGIN_WRITE_PROMETHEUS
+pkglib_LTLIBRARIES += write_prometheus.la
+write_prometheus_la_SOURCES = src/write_prometheus.c
+nodist_write_prometheus_la_SOURCES = \
+       prometheus.pb-c.c \
+       prometheus.pb-c.h
+write_prometheus_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_CPPFLAGS) $(BUILD_WITH_LIBMICROHTTPD_CPPFLAGS)
+write_prometheus_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_LDFLAGS) $(BUILD_WITH_LIBMICROHTTPD_LDFLAGS)
+write_prometheus_la_LIBADD = $(BUILD_WITH_LIBPROTOBUF_C_LIBS) $(BUILD_WITH_LIBMICROHTTPD_LIBS)
+endif
+
+if BUILD_PLUGIN_WRITE_REDIS
+pkglib_LTLIBRARIES += write_redis.la
+write_redis_la_SOURCES = src/write_redis.c
+write_redis_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBHIREDIS_CPPFLAGS)
+write_redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBHIREDIS_LDFLAGS)
+write_redis_la_LIBADD = -lhiredis
+endif
+
+if BUILD_PLUGIN_WRITE_RIEMANN
+pkglib_LTLIBRARIES += write_riemann.la
+write_riemann_la_SOURCES = \
+       src/write_riemann.c \
+       src/write_riemann_threshold.c \
+       src/write_riemann_threshold.h
+write_riemann_la_CFLAGS = $(AM_CFLAGS) $(LIBRIEMANN_CLIENT_CFLAGS)
+write_riemann_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBRIEMANN_CLIENT_LIBS)
+endif
+
+if BUILD_PLUGIN_WRITE_SENSU
+pkglib_LTLIBRARIES += write_sensu.la
+write_sensu_la_SOURCES = src/write_sensu.c
+write_sensu_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_WRITE_TSDB
+pkglib_LTLIBRARIES += write_tsdb.la
+write_tsdb_la_SOURCES = src/write_tsdb.c
+write_tsdb_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_XENCPU
+pkglib_LTLIBRARIES += xencpu.la
+xencpu_la_SOURCES = src/xencpu.c
+xencpu_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBXENCTL_CPPFLAGS)
+xencpu_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBXENCTL_LDFLAGS)
+xencpu_la_LIBADD = -lxenctrl
+endif
+
+if BUILD_PLUGIN_XMMS
+pkglib_LTLIBRARIES += xmms.la
+xmms_la_SOURCES = src/xmms.c
+xmms_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBXMMS_CFLAGS)
+xmms_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+xmms_la_LIBADD = $(BUILD_WITH_LIBXMMS_LIBS)
+endif
+
+if BUILD_PLUGIN_ZFS_ARC
+pkglib_LTLIBRARIES += zfs_arc.la
+zfs_arc_la_SOURCES = src/zfs_arc.c
+zfs_arc_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+if BUILD_FREEBSD
+zfs_arc_la_LIBADD = -lm
+endif
+if BUILD_SOLARIS
+zfs_arc_la_LIBADD = -lkstat
+endif
+endif
+
+if BUILD_PLUGIN_ZOOKEEPER
+pkglib_LTLIBRARIES += zookeeper.la
+zookeeper_la_SOURCES = src/zookeeper.c
+zookeeper_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+if BUILD_PLUGIN_ZONE
+pkglib_LTLIBRARIES += zone.la
+zone_la_SOURCES = src/zone.c
+zone_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+endif
+
+AM_V_POD2MAN_C = $(am__v_POD2MAN_C_@AM_V@)
+am__v_POD2MAN_C_ = $(am__v_POD2MAN_C_@AM_DEFAULT_V@)
+am__v_POD2MAN_C_0 = @echo "  POD2MAN " $@;
+am__v_POD2MAN_C_1 =
+
+.pod.1:
+       $(AM_V_POD2MAN_C)pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
+       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
+
+.pod.5:
+       $(AM_V_POD2MAN_C)pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
+               >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
+       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
+       then \
+               echo "$@ has some POD errors!"; false; \
+       fi
+
+V_PROTOC = $(v_protoc_@AM_V@)
+v_protoc_ = $(v_protoc_@AM_DEFAULT_V@)
+v_protoc_0 = @echo "  PROTOC  " $@;
+
+AM_V_PROTOC_C = $(am__v_PROTOC_C_@AM_V@)
+am__v_PROTOC_C_ = $(am__v_PROTOC_C_@AM_DEFAULT_V@)
+am__v_PROTOC_C_0 = @echo "  PROTOC-C" $@;
+am__v_PROTOC_C_1 =
+
+# Protocol buffer for the "pinba" plugin.
+if BUILD_PLUGIN_PINBA
+BUILT_SOURCES += src/pinba.pb-c.c src/pinba.pb-c.h
+
+src/pinba.pb-c.c src/pinba.pb-c.h: $(srcdir)/src/pinba.proto
+       $(AM_V_PROTOC_C)$(PROTOC_C) -I$(srcdir) --c_out . $(srcdir)/src/pinba.proto
+endif
+
+# Protocol buffer for the "write_prometheus" plugin.
+if BUILD_PLUGIN_WRITE_PROMETHEUS
+BUILT_SOURCES += prometheus.pb-c.c prometheus.pb-c.h
+
+prometheus.pb-c.c prometheus.pb-c.h: $(srcdir)/proto/prometheus.proto
+       $(AM_V_PROTOC_C)$(PROTOC_C) -I$(srcdir)/proto --c_out=$(builddir) $(srcdir)/proto/prometheus.proto
+endif
+
+if HAVE_PROTOC3
+if HAVE_GRPC_CPP
+BUILT_SOURCES += collectd.grpc.pb.cc collectd.pb.cc types.pb.cc
+
+collectd.grpc.pb.cc: $(srcdir)/proto/collectd.proto $(srcdir)/proto/types.proto
+       $(V_PROTOC)$(PROTOC) -I$(srcdir)/proto \
+               --grpc_out=$(builddir) --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN) $<
+
+collectd.pb.cc: $(srcdir)/proto/collectd.proto $(srcdir)/proto/types.proto
+       $(V_PROTOC)$(PROTOC) -I$(srcdir)/proto --cpp_out=$(builddir) $<
+
+types.pb.cc: $(srcdir)/proto/types.proto
+       $(V_PROTOC)$(PROTOC) -I$(srcdir)/proto --cpp_out=$(builddir) $<
+endif
+endif
 
 install-exec-hook:
        $(mkinstalldirs) $(DESTDIR)$(localstatedir)/run
        $(mkinstalldirs) $(DESTDIR)$(localstatedir)/lib/$(PACKAGE_NAME)
        $(mkinstalldirs) $(DESTDIR)$(localstatedir)/log
+       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
+       if test -e $(DESTDIR)$(sysconfdir)/collectd.conf; \
+       then \
+               $(INSTALL) -m 0640 $(srcdir)/src/collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf.pkg-orig; \
+       else \
+               $(INSTALL) -m 0640 $(srcdir)/src/collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf; \
+       fi; \
+       $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
+       $(INSTALL) -m 0644 $(srcdir)/src/types.db $(DESTDIR)$(pkgdatadir)/types.db;
+       $(INSTALL) -m 0644 $(srcdir)/src/postgresql_default.conf \
+               $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
+
+uninstall-hook:
+       rm -f $(DESTDIR)$(pkgdatadir)/types.db;
+       rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
+       rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
+
+all-local: @PERL_BINDINGS@
+
+install-exec-local:
+       [ ! -f buildperl/Makefile ] || ( cd buildperl && $(MAKE) install )
+
+# Perl 'make uninstall' does not work as well as wanted.
+# So we do the work here.
+uninstall-local:
+       @PERL@ -I$(DESTDIR)$(prefix) $(srcdir)/bindings/perl/uninstall_mod.pl Collectd
+       find $(DESTDIR)$(prefix) -name "perllocal.pod" -exec rm {} \;
+
+clean-local:
+       rm -rf buildperl
+
+perl: buildperl/Makefile
+       cd buildperl && $(MAKE)
+
+buildperl/Makefile: .perl-directory-stamp buildperl/Makefile.PL \
+       $(top_builddir)/config.status
+       @# beautify the output a bit
+       @echo 'cd buildperl && @PERL@ Makefile.PL @PERL_BINDINGS_OPTIONS@'
+       @cd buildperl && ( if ! @PERL@ Makefile.PL @PERL_BINDINGS_OPTIONS@; then \
+                       echo ""; \
+                       echo 'Check whether you have set $$PERL_MM_OPT in your environment and try using ./configure --with-perl-bindings=""'; \
+                       echo ""; \
+               fi )
+
+buildperl/Makefile.PL: .perl-directory-stamp $(top_builddir)/config.status
+
+.perl-directory-stamp:
+       if test ! -d buildperl; then \
+         mkdir -p buildperl/Collectd/Plugins; \
+         cp $(srcdir)/bindings/perl/lib/Collectd.pm buildperl/; \
+         cp $(srcdir)/bindings/perl/Makefile.PL buildperl/; \
+         cp $(srcdir)/bindings/perl/lib/Collectd/Unixsock.pm buildperl/Collectd/; \
+         cp $(srcdir)/bindings/perl/lib/Collectd/Plugins/OpenVZ.pm buildperl/Collectd/Plugins/; \
+       fi
+       touch $@
+
+.PHONY: perl
+
+
+if BUILD_WITH_JAVA
+dist_noinst_JAVA = \
+       bindings/java/org/collectd/api/Collectd.java \
+       bindings/java/org/collectd/api/CollectdConfigInterface.java \
+       bindings/java/org/collectd/api/CollectdFlushInterface.java \
+       bindings/java/org/collectd/api/CollectdInitInterface.java \
+       bindings/java/org/collectd/api/CollectdLogInterface.java \
+       bindings/java/org/collectd/api/CollectdMatchFactoryInterface.java \
+       bindings/java/org/collectd/api/CollectdMatchInterface.java \
+       bindings/java/org/collectd/api/CollectdNotificationInterface.java \
+       bindings/java/org/collectd/api/CollectdReadInterface.java \
+       bindings/java/org/collectd/api/CollectdShutdownInterface.java \
+       bindings/java/org/collectd/api/CollectdTargetFactoryInterface.java \
+       bindings/java/org/collectd/api/CollectdTargetInterface.java \
+       bindings/java/org/collectd/api/CollectdWriteInterface.java \
+       bindings/java/org/collectd/api/DataSet.java \
+       bindings/java/org/collectd/api/DataSource.java \
+       bindings/java/org/collectd/api/Notification.java \
+       bindings/java/org/collectd/api/OConfigItem.java \
+       bindings/java/org/collectd/api/OConfigValue.java \
+       bindings/java/org/collectd/api/PluginData.java \
+       bindings/java/org/collectd/api/ValueList.java \
+       bindings/java/org/collectd/java/GenericJMX.java \
+       bindings/java/org/collectd/java/GenericJMXConfConnection.java \
+       bindings/java/org/collectd/java/GenericJMXConfMBean.java \
+       bindings/java/org/collectd/java/GenericJMXConfValue.java \
+       bindings/java/org/collectd/java/JMXMemory.java
+
+collectd-api.jar: classnoinst.stamp
+       $(JAR) cf $(JARFLAGS) $@ org/collectd/api/*.class
+
+generic-jmx.jar: classnoinst.stamp
+       $(JAR) cf $(JARFLAGS) $@ org/collectd/java/*.class
 
-maintainer-clean-local:
-       -rm -f INSTALL
-       -rm -f aclocal.m4
+jar_DATA = collectd-api.jar generic-jmx.jar
+endif
diff --git a/README b/README
index 2fa8954..fb3aa27 100644 (file)
--- a/README
+++ b/README
@@ -198,14 +198,19 @@ Features
       Queries very detailed usage statistics from wireless LAN adapters and
       interfaces that use the Atheros chipset and the MadWifi driver.
 
-    - md
-      Linux software-RAID device information (number of active, failed, spare
-      and missing disks).
-
     - mbmon
       Motherboard sensors: temperature, fan speed and voltage information,
       using mbmon(1).
 
+    - mcelog
+      Monitor machine check exceptions (hardware errors detected by hardware
+      and reported to software) reported by mcelog and generate appropriate
+      notifications when machine check exceptions are detected.
+
+    - md
+      Linux software-RAID device information (number of active, failed, spare
+      and missing disks).
+
     - memcachec
       Query and parse data from a memcache daemon (memcached).
 
@@ -283,6 +288,15 @@ Features
     - oracle
       Query data from an Oracle database.
 
+    - ovs_events
+      The plugin monitors the link status of Open vSwitch (OVS) connected
+      interfaces, dispatches the values to collectd and sends the notification
+      whenever the link state change occurs in the OVS database. It requires
+      YAJL library to be installed.
+      Detailed instructions for installing and setting up Open vSwitch, see
+      OVS documentation.
+      <http://openvswitch.org/support/dist-docs/INSTALL.rst.html>
+
     - perl
       The perl plugin implements a Perl-interpreter into collectd. You can
       write your own plugins in Perl and return arbitrary values using this
@@ -500,6 +514,10 @@ Features
     - write_mongodb
       Sends data to MongoDB, a NoSQL database.
 
+    - write_prometheus
+      Publish values using an embedded HTTP server, in a format compatible
+      with Prometheus' collectd_exporter.
+
     - write_redis
       Sends the values to a Redis key-value database server.
 
@@ -776,6 +794,10 @@ Prerequisites
     Used by the `memcachec' plugin to connect to a memcache daemon.
     <http://tangent.org/552/libmemcached.html>
 
+  * libmicrohttpd (optional)
+    Used by the write_prometheus plugin to run an http daemon.
+    <http://www.gnu.org/software/libmicrohttpd/>
+
   * libmnl (optional)
     Used by the `netlink' plugin.
     <http://www.netfilter.org/projects/libmnl/>
@@ -913,8 +935,8 @@ Prerequisites
     <http://www.xmms.org/>
 
   * libyajl (optional)
-    Parse JSON data. This is needed for the `ceph', `curl_json' and
-    `log_logstash' plugins.
+    Parse JSON data. This is needed for the `ceph', `curl_json', 'ovs_events'
+    and `log_logstash' plugins.
     <http://github.com/lloyd/yajl>
 
   * libvarnish (optional)
diff --git a/bindings/Makefile.am b/bindings/Makefile.am
deleted file mode 100644 (file)
index 07373e8..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-SUBDIRS =
-
-if BUILD_WITH_JAVA
-SUBDIRS += java
-endif
-
-EXTRA_DIST = perl/Makefile.PL \
-            perl/uninstall_mod.pl \
-            perl/lib/Collectd.pm \
-            perl/lib/Collectd/Unixsock.pm \
-            perl/lib/Collectd/Plugins/Monitorus.pm \
-            perl/lib/Collectd/Plugins/OpenVZ.pm
-
-CLEANFILES = \
-       buildperl/Collectd.pm \
-       buildperl/Collectd/Plugins/OpenVZ.pm \
-       buildperl/Collectd/Unixsock.pm \
-       buildperl/Makefile.PL \
-       .perl-directory-stamp
-
-DISTCLEANFILES = \
-       buildperl/Collectd.pm \
-       buildperl/Collectd/Plugins/OpenVZ.pm \
-       buildperl/Collectd/Unixsock.pm \
-       buildperl/Makefile.PL \
-       .perl-directory-stamp
-
-all-local: @PERL_BINDINGS@
-
-
-install-exec-local:
-       [ ! -f buildperl/Makefile ] || ( cd buildperl && $(MAKE) install )
-
-# Perl 'make uninstall' does not work as well as wanted.
-# So we do the work here.
-uninstall-local:
-       @PERL@ -I$(DESTDIR)$(prefix) $(srcdir)/perl/uninstall_mod.pl Collectd
-       find $(DESTDIR)$(prefix) -name "perllocal.pod" -exec rm {} \;
-
-clean-local:
-       rm -rf buildperl
-
-perl: buildperl/Makefile
-       cd buildperl && $(MAKE)
-
-buildperl/Makefile: .perl-directory-stamp buildperl/Makefile.PL \
-       $(top_builddir)/config.status
-       @# beautify the output a bit
-       @echo 'cd buildperl && @PERL@ Makefile.PL @PERL_BINDINGS_OPTIONS@'
-       @cd buildperl && ( if ! @PERL@ Makefile.PL @PERL_BINDINGS_OPTIONS@; then \
-                       echo ""; \
-                       echo 'Check whether you have set $$PERL_MM_OPT in your environment and try using ./configure --with-perl-bindings=""'; \
-                       echo ""; \
-               fi )
-
-buildperl/Makefile.PL: .perl-directory-stamp $(top_builddir)/config.status
-
-.perl-directory-stamp:
-       if test ! -d buildperl; then \
-         mkdir -p buildperl/Collectd/Plugins; \
-         cp $(srcdir)/perl/lib/Collectd.pm buildperl/; \
-         cp $(srcdir)/perl/Makefile.PL buildperl/; \
-         cp $(srcdir)/perl/lib/Collectd/Unixsock.pm buildperl/Collectd/; \
-         cp $(srcdir)/perl/lib/Collectd/Plugins/OpenVZ.pm buildperl/Collectd/Plugins/; \
-       fi
-       touch $@
-
-.PHONY: perl
-
diff --git a/bindings/java/Makefile.am b/bindings/java/Makefile.am
deleted file mode 100644 (file)
index 8d2e49d..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-EXTRA_DIST = org/collectd/api/CollectdConfigInterface.java \
-            org/collectd/api/CollectdFlushInterface.java \
-            org/collectd/api/CollectdInitInterface.java \
-            org/collectd/api/Collectd.java \
-            org/collectd/api/CollectdLogInterface.java \
-            org/collectd/api/CollectdMatchFactoryInterface.java \
-            org/collectd/api/CollectdMatchInterface.java \
-            org/collectd/api/CollectdNotificationInterface.java \
-            org/collectd/api/CollectdReadInterface.java \
-            org/collectd/api/CollectdShutdownInterface.java \
-            org/collectd/api/CollectdTargetFactoryInterface.java \
-            org/collectd/api/CollectdTargetInterface.java \
-            org/collectd/api/CollectdWriteInterface.java \
-            org/collectd/api/DataSet.java \
-            org/collectd/api/DataSource.java \
-            org/collectd/api/Notification.java \
-            org/collectd/api/OConfigItem.java \
-            org/collectd/api/OConfigValue.java \
-            org/collectd/api/PluginData.java \
-            org/collectd/api/ValueList.java \
-            org/collectd/java/GenericJMXConfConnection.java \
-            org/collectd/java/GenericJMXConfMBean.java \
-            org/collectd/java/GenericJMXConfValue.java \
-            org/collectd/java/GenericJMX.java \
-            org/collectd/java/JMXMemory.java
-
-java-build-stamp: $(srcdir)/org/collectd/api/*.java $(srcdir)/org/collectd/java/*.java
-       $(JAVAC) -d "." "$(srcdir)/org/collectd/api"/*.java
-       $(JAVAC) -d "." "$(srcdir)/org/collectd/java"/*.java
-       mkdir -p .libs
-       $(JAR) cf .libs/collectd-api.jar "org/collectd/api"/*.class
-       $(JAR) cf .libs/generic-jmx.jar "org/collectd/java"/*.class
-       touch "$@"
-
-all-local: java-build-stamp
-
-install-exec-local: java-build-stamp
-       mkdir -p "$(DESTDIR)$(pkgdatadir)/java"
-       $(INSTALL) -m 644 .libs/collectd-api.jar \
-               "$(DESTDIR)$(pkgdatadir)/java"
-       $(INSTALL) -m 644 .libs/generic-jmx.jar \
-               "$(DESTDIR)$(pkgdatadir)/java"
-
-uninstall-local:
-       rm -f "$(DESTDIR)$(pkgdatadir)/java/collectd-api.jar"
-       rm -f "$(DESTDIR)$(pkgdatadir)/java/generic-jmx.jar"
-       rmdir "$(DESTDIR)$(pkgdatadir)/java" || true
-
-clean-local:
-       rm -f "org/collectd/api"/*.class
-       rm -f "org/collectd/java"/*.class
-       rm -f .libs
-       rm -f "java-build-stamp"
index 9eb9739..be90e03 100644 (file)
@@ -357,8 +357,7 @@ AC_CHECK_HEADERS([netinet/udp.h], [], [],
 
 # For cpu modules
 AC_CHECK_HEADERS([sys/dkstat.h])
-if test "x$ac_system" = "xDarwin"
-then
+if test "x$ac_system" = "xDarwin"; then
   AC_CHECK_HEADERS(
     [[ \
       mach/mach_init.h \
@@ -424,8 +423,7 @@ AC_CHECK_HEADERS([net/if.h], [], [],
   ]]
 )
 
-if test "x$ac_system" = "xLinux"
-then
+if test "x$ac_system" = "xLinux"; then
   # For hddtemp module
   AC_CHECK_HEADERS([linux/major.h])
 
@@ -911,8 +909,7 @@ AC_CHECK_FUNCS([clock_gettime],
   [have_clock_gettime="no"]
 )
 
-if test "x$have_clock_gettime" = "xno"
-then
+if test "x$have_clock_gettime" = "xno"; then
   AC_CHECK_LIB([rt], [clock_gettime],
     [
       clock_gettime_needs_rt="yes"
@@ -921,8 +918,7 @@ then
   )
 fi
 
-if test "x$have_clock_gettime" = "xno"
-then
+if test "x$have_clock_gettime" = "xno"; then
   AC_CHECK_LIB([posix4], [clock_gettime],
     [
       clock_gettime_needs_posix4="yes"
@@ -931,8 +927,7 @@ then
   )
 fi
 
-if test "x$have_clock_gettime" = "xyes"
-then
+if test "x$have_clock_gettime" = "xyes"; then
   AC_DEFINE([HAVE_CLOCK_GETTIME], [1], [Define if the clock_gettime(2) function is available.])
 fi
 
@@ -965,15 +960,13 @@ AC_CHECK_FUNCS([syslog], [have_syslog="yes"], [have_syslog="no"])
 AC_CHECK_FUNCS([thread_info], [have_thread_info="yes"], [have_thread_info="no"])
 
 # Check for strptime {{{
-if test "x$GCC" = "xyes"
-then
+if test "x$GCC" = "xyes"; then
   SAVE_CFLAGS="$CFLAGS"
   CFLAGS="$CFLAGS -Wall -Wextra -Werror"
 fi
 
 AC_CHECK_FUNCS([strptime], [have_strptime="yes"], [have_strptime="no"])
-if test "x$have_strptime" = "xyes"
-then
+if test "x$have_strptime" = "xyes"; then
   AC_CACHE_CHECK([whether strptime is exported by default],
     [c_cv_have_strptime_default],
     [
@@ -993,8 +986,7 @@ then
   )
 fi
 
-if test "x$have_strptime" = "xyes" && test "x$c_cv_have_strptime_default" = "xno"
-then
+if test "x$have_strptime" = "xyes" && test "x$c_cv_have_strptime_default" = "xno"; then
   AC_CACHE_CHECK([whether strptime needs standards mode],
     [c_cv_have_strptime_standards],
     [
@@ -1034,15 +1026,13 @@ then
   fi
 fi
 
-if test "x$GCC" = "xyes"
-then
+if test "x$GCC" = "xyes"; then
   CFLAGS="$SAVE_CFLAGS"
 fi
 # }}} Check for strptime
 
 AC_MSG_CHECKING([for sysctl kern.cp_times])
-if test -x /sbin/sysctl
-then
+if test -x /sbin/sysctl; then
   /sbin/sysctl kern.cp_times >/dev/null 2>&1
   if test $? -eq 0; then
     AC_MSG_RESULT([yes])
@@ -1055,8 +1045,7 @@ else
 fi
 
 AC_MSG_CHECKING([for sysctl kern.cp_time])
-if test -x /sbin/sysctl
-then
+if test -x /sbin/sysctl; then
   /sbin/sysctl kern.cp_time >/dev/null 2>&1
   if test $? -eq 0
   then
@@ -1286,46 +1275,46 @@ AC_ARG_WITH([fp-layout],
 )
 
 if test "x$fp_layout_type" = "xunknown"; then
-AC_CACHE_CHECK([if doubles are stored in x86 representation],
-  [c_cv_fp_layout_need_nothing],
-  [
-    AC_RUN_IFELSE(
-      [
-        AC_LANG_PROGRAM(
-          [[
-            #include <stdlib.h>
-            #include <stdio.h>
-            #include <string.h>
-            #include <stdint.h>
-            #include <inttypes.h>
-            #include <stdbool.h>
-          ]],
-          [[
-            uint64_t i0;
-            uint64_t i1;
-            uint8_t c[8];
-            double d;
-
-            d = 8.642135e130;
-            memcpy ((void *) &i0, (void *) &d, 8);
-
-            i1 = i0;
-            memcpy ((void *) c, (void *) &i1, 8);
-
-            if ((c[0] == 0x2f) && (c[1] == 0x25)
-                && (c[2] == 0xc0) && (c[3] == 0xc7)
-                && (c[4] == 0x43) && (c[5] == 0x2b)
-                && (c[6] == 0x1f) && (c[7] == 0x5b))
-              return (0);
-            return (1);
-          ]]
-        )
-      ],
-      [c_cv_fp_layout_need_nothing="yes"],
-      [c_cv_fp_layout_need_nothing="no"]
-    )
-  ]
-)
+  AC_CACHE_CHECK([if doubles are stored in x86 representation],
+    [c_cv_fp_layout_need_nothing],
+    [
+      AC_RUN_IFELSE(
+        [
+          AC_LANG_PROGRAM(
+            [[
+              #include <stdlib.h>
+              #include <stdio.h>
+              #include <string.h>
+              #include <stdint.h>
+              #include <inttypes.h>
+              #include <stdbool.h>
+            ]],
+            [[
+              uint64_t i0;
+              uint64_t i1;
+              uint8_t c[8];
+              double d;
+
+              d = 8.642135e130;
+              memcpy ((void *) &i0, (void *) &d, 8);
+
+              i1 = i0;
+              memcpy ((void *) c, (void *) &i1, 8);
+
+              if ((c[0] == 0x2f) && (c[1] == 0x25)
+                  && (c[2] == 0xc0) && (c[3] == 0xc7)
+                  && (c[4] == 0x43) && (c[5] == 0x2b)
+                  && (c[6] == 0x1f) && (c[7] == 0x5b))
+                return (0);
+              return (1);
+            ]]
+          )
+        ],
+        [c_cv_fp_layout_need_nothing="yes"],
+        [c_cv_fp_layout_need_nothing="no"]
+      )
+    ]
+  )
 fi
 
 if test "x$c_cv_fp_layout_need_nothing" = "xyes"; then
@@ -1762,36 +1751,40 @@ SAVE_LDFLAGS="$LDFLAGS"
 LDFLAGS="$LDFLAGS -lpthread"
 
 AC_MSG_CHECKING([for pthread_setname_np])
-       have_pthread_setname_np="no"
-       AC_LINK_IFELSE([AC_LANG_PROGRAM(
-[[
-#define _GNU_SOURCE
-#include <pthread.h>
-]],
-[[
-        pthread_setname_np((pthread_t) {0}, "conftest");
-]]
-       )], [
-               have_pthread_setname_np="yes"
-               AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [pthread_setname_np() is available.])
-       ])
+have_pthread_setname_np="no"
+AC_LINK_IFELSE(
+  [
+    AC_LANG_PROGRAM(
+      [[
+        #define _GNU_SOURCE
+        #include <pthread.h>
+      ]],
+      [[pthread_setname_np((pthread_t) {0}, "conftest");]]
+    )
+  ],
+  [
+    have_pthread_setname_np="yes"
+    AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [pthread_setname_np() is available.])
+  ]
+)
 
 AC_MSG_RESULT([$have_pthread_setname_np])
 
 # check for pthread_set_name_np(3) (FreeBSD)
 AC_MSG_CHECKING([for pthread_set_name_np])
-       have_pthread_set_name_np="no"
-       AC_LINK_IFELSE([AC_LANG_PROGRAM(
-[[
-#include <pthread_np.h>
-]],
-[[
-        pthread_set_name_np((pthread_t) {0}, "conftest");
-]]
-       )], [
-               have_pthread_set_name_np="yes"
-               AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [pthread_set_name_np() is available.])
-       ])
+have_pthread_set_name_np="no"
+AC_LINK_IFELSE(
+  [
+    AC_LANG_PROGRAM(
+      [[#include <pthread_np.h>]],
+      [[pthread_set_name_np((pthread_t) {0}, "conftest");]]
+    )
+   ],
+  [
+    have_pthread_set_name_np="yes"
+    AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [pthread_set_name_np() is available.])
+  ]
+)
 AC_MSG_RESULT([$have_pthread_set_name_np])
 
 LDFLAGS="$SAVE_LDFLAGS"
@@ -2969,7 +2962,7 @@ else
       PKG_CHECK_MODULES([LUA], [lua-5.3],
         [with_liblua="yes"],
         [
-         PKG_CHECK_MODULES([LUA], [lua5.3],
+          PKG_CHECK_MODULES([LUA], [lua5.3],
             [with_liblua="yes"],
             [
               PKG_CHECK_MODULES([LUA], [lua-5.2],
@@ -3153,29 +3146,25 @@ with_libmicrohttpd_cppflags=""
 with_libmicrohttpd_ldflags=""
 AC_ARG_WITH([libmicrohttpd], [AS_HELP_STRING([--with-libmicrohttpd@<:@=PREFIX@:>@], [Path to libmicrohttpd.])],
   [
-    if test "x$withval" != "xno" && test "x$withval" != "xyes"
-    then
+    if test "x$withval" != "xno" && test "x$withval" != "xyes"; then
       with_libmicrohttpd_cppflags="-I$withval/include"
       with_libmicrohttpd_ldflags="-L$withval/lib"
       with_libmicrohttpd="yes"
     fi
-    if test "x$withval" = "xno"
-    then
+    if test "x$withval" = "xno"; then
       with_libmicrohttpd="no (disabled on command line)"
     fi
   ],
   [withval="yes"]
 )
-if test "x$withval" = "xyes"
-then
-PKG_CHECK_MODULES([MICROHTTPD], [libmicrohttpd],
-  [with_libmicrohttpd="yes"],
-  [with_libmicrohttpd="no (pkg-config could not find libmicrohttpd)"]
-)
+if test "x$withval" = "xyes"; then
+  PKG_CHECK_MODULES([MICROHTTPD], [libmicrohttpd],
+    [with_libmicrohttpd="yes"],
+    [with_libmicrohttpd="no (pkg-config could not find libmicrohttpd)"]
+  )
 fi
 
-if test "x$MICROHTTPD_LIBS" = "x"
-then
+if test "x$MICROHTTPD_LIBS" = "x"; then
   MICROHTTPD_LIBS="-lmicrohttpd"
 fi
 
@@ -3186,18 +3175,18 @@ CPPFLAGS="$with_libmicrohttpd_cppflags $MICROHTTPD_CFLAGS"
 LDFLAGS="$with_libmicrohttpd_ldflags $LDFLAGS"
 LIBS="$LIBS $MICROHTTPD_LIBS"
 
-if test "x$with_libmicrohttpd" = "xyes"
-then
+if test "x$with_libmicrohttpd" = "xyes"; then
   AC_CHECK_HEADERS([microhttpd.h],
-                   [with_libmicrohttpd="yes"],
-                   [with_libmicrohttpd="no (<microhttpd.h> not found)"])
+   [with_libmicrohttpd="yes"],
+   [with_libmicrohttpd="no (<microhttpd.h> not found)"]
+  )
 fi
 
-if test "x$with_libmicrohttpd" = "xyes"
-then
+if test "x$with_libmicrohttpd" = "xyes"; then
   AC_CHECK_LIB([microhttpd], [MHD_start_daemon],
-               [with_libmicrohttpd="yes"],
-               [with_libmicrohttpd="no (libmicrohttpd not found)"])
+    [with_libmicrohttpd="yes"],
+    [with_libmicrohttpd="no (libmicrohttpd not found)"]
+  )
 fi
 
 CPPFLAGS="$SAVE_CPPFLAGS"
@@ -3246,8 +3235,7 @@ if test "x$with_libmodbus" = "xuse_pkgconfig"; then
   fi
 
   with_libmodbus_libs="`$PKG_CONFIG --libs 'libmodbus'`"
-  if test $? -ne 0
-  then
+  if test $? -ne 0; then
     with_libmodbus="no ($PKG_CONFIG failed)"
   fi
 fi
@@ -5353,6 +5341,11 @@ if test "x$with_libyajl" = "xyes"; then
     [with_libyajl="no (yajl/yajl_parse.h not found)"]
   )
 
+  AC_CHECK_HEADERS([yajl/yajl_tree.h],
+    [with_libyajl2="yes"],
+    [with_libyajl2="no (yajl/yajl_tree.h not found)"]
+  )
+
   AC_CHECK_HEADERS([yajl/yajl_version.h])
 
   CPPFLAGS="$SAVE_CPPFLAGS"
@@ -5367,6 +5360,11 @@ if test "x$with_libyajl" = "xyes"; then
     [with_libyajl="no (Symbol 'yajl_alloc' not found)"]
   )
 
+  AC_CHECK_LIB([yajl], [yajl_tree_parse],
+    [with_libyajl2="yes"],
+    [with_libyajl2="no (Symbol 'yajl_tree_parse' not found)"]
+  )
+
   LDFLAGS="$SAVE_LDFLAGS"
 fi
 
@@ -5889,10 +5887,12 @@ plugin_ipvs="no"
 plugin_irq="no"
 plugin_load="no"
 plugin_log_logstash="no"
+plugin_mcelog="no"
 plugin_memory="no"
 plugin_multimeter="no"
 plugin_nfs="no"
 plugin_numa="no"
+plugin_ovs_events="no"
 plugin_perl="no"
 plugin_pinba="no"
 plugin_processes="no"
@@ -5937,6 +5937,7 @@ if test "x$ac_system" = "xLinux"; then
   plugin_irq="yes"
   plugin_load="yes"
   plugin_lvm="yes"
+  plugin_mcelog="yes"
   plugin_memory="yes"
   plugin_nfs="yes"
   plugin_numa="yes"
@@ -6080,6 +6081,7 @@ if test "x$have_sysctl" = "xyes"; then
     plugin_swap="yes"
   fi
 fi
+
 if test "x$have_sysctlbyname" = "xyes"; then
   plugin_contextswitch="yes"
   plugin_cpu="yes"
@@ -6138,6 +6140,10 @@ if test "x$with_libyajl" = "xyes"; then
   plugin_log_logstash="yes"
 fi
 
+if test "x$with_libyajl" = "xyes" && test "x$with_libyajl2" = "xyes"; then
+  plugin_ovs_events="yes"
+fi
+
 if test "x$with_libperl" = "xyes" && test "x$c_cv_have_perl_ithreads" = "xyes"; then
   plugin_perl="yes"
 fi
@@ -6298,6 +6304,7 @@ AC_PLUGIN([match_regex],         [yes],                     [The regex match])
 AC_PLUGIN([match_timediff],      [yes],                     [The timediff match])
 AC_PLUGIN([match_value],         [yes],                     [The value match])
 AC_PLUGIN([mbmon],               [yes],                     [Query mbmond])
+AC_PLUGIN([mcelog],              [$plugin_mcelog],          [Machine Check Exceptions notifications])
 AC_PLUGIN([md],                  [$have_linux_raid_md_u_h], [md (Linux software RAID) devices])
 AC_PLUGIN([memcachec],           [$with_libmemcached],      [memcachec statistics])
 AC_PLUGIN([memcached],           [yes],                     [memcached statistics])
@@ -6323,6 +6330,7 @@ AC_PLUGIN([onewire],             [$with_libowcapi],         [OneWire sensor stat
 AC_PLUGIN([openldap],            [$with_libldap],           [OpenLDAP statistics])
 AC_PLUGIN([openvpn],             [yes],                     [OpenVPN client statistics])
 AC_PLUGIN([oracle],              [$with_oracle],            [Oracle plugin])
+AC_PLUGIN([ovs_events],          [$plugin_ovs_events],      [OVS events plugin])
 AC_PLUGIN([perl],                [$plugin_perl],            [Embed a Perl interpreter])
 AC_PLUGIN([pf],                  [$have_net_pfvar_h],       [BSD packet filter (PF) statistics])
 # FIXME: Check for libevent, too.
@@ -6548,15 +6556,8 @@ AC_SUBST([AM_CXXFLAGS])
 
 AC_CONFIG_FILES([ \
   Makefile \
-  bindings/Makefile \
-  bindings/java/Makefile \
-  proto/Makefile \
-  src/Makefile \
   src/collectd.conf \
-  src/daemon/Makefile \
-  src/libcollectdclient/Makefile \
   src/libcollectdclient/libcollectdclient.pc \
-  src/liboconfig/Makefile \
 ])
 
 AC_OUTPUT
@@ -6707,7 +6708,7 @@ AC_MSG_RESULT([    gps . . . . . . . . . $enable_gps])
 AC_MSG_RESULT([    grpc  . . . . . . . . $enable_grpc])
 AC_MSG_RESULT([    hddtemp . . . . . . . $enable_hddtemp])
 AC_MSG_RESULT([    hugepages . . . . . . $enable_hugepages])
-AC_MSG_RESULT([    intel_rdt. . . . .  . $enable_intel_rdt])
+AC_MSG_RESULT([    intel_rdt . . . . . . $enable_intel_rdt])
 AC_MSG_RESULT([    interface . . . . . . $enable_interface])
 AC_MSG_RESULT([    ipc . . . . . . . . . $enable_ipc])
 AC_MSG_RESULT([    ipmi  . . . . . . . . $enable_ipmi])
@@ -6728,6 +6729,7 @@ AC_MSG_RESULT([    match_regex . . . . . $enable_match_regex])
 AC_MSG_RESULT([    match_timediff  . . . $enable_match_timediff])
 AC_MSG_RESULT([    match_value . . . . . $enable_match_value])
 AC_MSG_RESULT([    mbmon . . . . . . . . $enable_mbmon])
+AC_MSG_RESULT([    mcelog  . . . . . . . $enable_mcelog])
 AC_MSG_RESULT([    md  . . . . . . . . . $enable_md])
 AC_MSG_RESULT([    memcachec . . . . . . $enable_memcachec])
 AC_MSG_RESULT([    memcached . . . . . . $enable_memcached])
@@ -6753,6 +6755,7 @@ AC_MSG_RESULT([    onewire . . . . . . . $enable_onewire])
 AC_MSG_RESULT([    openldap  . . . . . . $enable_openldap])
 AC_MSG_RESULT([    openvpn . . . . . . . $enable_openvpn])
 AC_MSG_RESULT([    oracle  . . . . . . . $enable_oracle])
+AC_MSG_RESULT([    ovs_events  . . . . . $enable_ovs_events])
 AC_MSG_RESULT([    perl  . . . . . . . . $enable_perl])
 AC_MSG_RESULT([    pf  . . . . . . . . . $enable_pf])
 AC_MSG_RESULT([    pinba . . . . . . . . $enable_pinba])
index 09cc3b1..8dc778b 100644 (file)
@@ -88,6 +88,7 @@
 %define with_lvm 0%{!?_without_lvm:1}
 %define with_madwifi 0%{!?_without_madwifi:1}
 %define with_mbmon 0%{!?_without_mbmon:1}
+%define with_mcelog 0%{!?_without_mcelog:1}
 %define with_md 0%{!?_without_md:1}
 %define with_memcachec 0%{!?_without_memcachec:1}
 %define with_memcached 0%{!?_without_memcached:1}
 Summary:       Statistics collection and monitoring daemon
 Name:          collectd
 Version:       5.7.0
-Release:       2%{?dist}
+Release:       3%{?dist}
 URL:           https://collectd.org
 Source:                https://collectd.org/files/%{name}-%{version}.tar.bz2
 License:       GPLv2
@@ -538,6 +539,16 @@ This plugin collects size of â€śLogical Volumes” (LV) and â€śVolume Groups”
 of Linux' â€śLogical Volume Manager” (LVM).
 %endif
 
+%if %{with_mcelog}
+%package mcelog
+Summary:       Mcelog plugin for collectd
+Group:         System Environment/Daemons
+Requires:      %{name}%{?_isa} = %{version}-%{release}
+%description mcelog
+This plugin monitors machine check exceptions reported by mcelog and generates
+appropriate notifications when machine check exceptions are detected.
+%endif
+
 %if %{with_memcachec}
 %package memcachec
 Summary:       Memcachec plugin for collectd
@@ -1279,6 +1290,12 @@ Collectd utilities
 %define _with_mbmon --disable-mbmon
 %endif
 
+%if %{with_mcelog}
+%define _with_mcelog --enable-mcelog
+%else
+%define _with_mbmon --disable-mcelog
+%endif
+
 %if %{with_md}
 %define _with_md --enable-md
 %else
@@ -1834,6 +1851,7 @@ Collectd utilities
        %{?_with_lvm} \
        %{?_with_madwifi} \
        %{?_with_mbmon} \
+       %{?_with_mcelog} \
        %{?_with_md} \
        %{?_with_memcachec} \
        %{?_with_memcached} \
@@ -2133,6 +2151,9 @@ fi
 %if %{with_mbmon}
 %{_libdir}/%{name}/mbmon.so
 %endif
+%if %{with_mcelog}
+%{_libdir}/%{name}/mcelog.so
+%endif
 %if %{with_md}
 %{_libdir}/%{name}/md.so
 %endif
@@ -2586,6 +2607,9 @@ fi
 %doc contrib/
 
 %changelog
+* Sat Dec 31 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.0-3
+- Add new mcelog plugin
+
 * Tue Nov 29 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.0-2
 - Disable redis plugin on RHEL 6, hiredis has been retired from EPEL6
 
diff --git a/m4/.gitignore b/m4/.gitignore
new file mode 100644 (file)
index 0000000..f935021
--- /dev/null
@@ -0,0 +1 @@
+!.gitignore
diff --git a/proto/Makefile.am b/proto/Makefile.am
deleted file mode 100644 (file)
index 62d3bed..0000000
+++ /dev/null
@@ -1 +0,0 @@
-EXTRA_DIST = collectd.proto types.proto prometheus.proto
diff --git a/src/Makefile.am b/src/Makefile.am
deleted file mode 100644 (file)
index 0fab4b3..0000000
+++ /dev/null
@@ -1,1523 +0,0 @@
-SUBDIRS = libcollectdclient liboconfig daemon
-
-PLUGIN_LDFLAGS = -module -avoid-version -export-symbols-regex '\<module_register\>'
-
-AM_CPPFLAGS = -I$(srcdir)/daemon
-AM_CPPFLAGS += -DPREFIX='"${prefix}"'
-AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
-AM_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
-AM_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
-if BUILD_FEATURE_DAEMON
-AM_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
-endif
-AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
-AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
-
-LOG_COMPILER = env VALGRIND="@VALGRIND@" $(abs_top_srcdir)/testwrapper.sh
-
-V_PROTOC = $(v_protoc_@AM_V@)
-v_protoc_ = $(v_protoc_@AM_DEFAULT_V@)
-v_protoc_0 = @echo "  PROTOC  " $@;
-
-noinst_LTLIBRARIES =
-check_PROGRAMS =
-TESTS =
-
-noinst_LTLIBRARIES += libformat_graphite.la
-libformat_graphite_la_SOURCES  = utils_format_graphite.c utils_format_graphite.h
-libformat_graphite_la_CPPFLAGS = $(AM_CPPFLAGS)
-libformat_graphite_la_LDFLAGS  = $(AM_LDFLAGS)
-check_PROGRAMS += test_format_graphite
-TESTS += test_format_graphite
-test_format_graphite_SOURCES = utils_format_graphite_test.c testing.h
-test_format_graphite_LDADD = libformat_graphite.la daemon/libmetadata.la daemon/libplugin_mock.la -lm
-
-noinst_LTLIBRARIES += libformat_json.la
-libformat_json_la_SOURCES   = utils_format_json.c utils_format_json.h
-libformat_json_la_CPPFLAGS  = $(AM_CPPFLAGS)
-libformat_json_la_LDFLAGS   = $(AM_LDFLAGS)
-libformat_json_la_LIBADD    =
-if BUILD_WITH_LIBYAJL
-libformat_json_la_CPPFLAGS += $(BUILD_WITH_LIBYAJL_CPPFLAGS)
-libformat_json_la_LDFLAGS  += $(BUILD_WITH_LIBYAJL_LDFLAGS)
-libformat_json_la_LIBADD   += $(BUILD_WITH_LIBYAJL_LIBS)
-check_PROGRAMS += test_format_json
-TESTS += test_format_json
-test_format_json_SOURCES = utils_format_json_test.c testing.h
-test_format_json_LDADD = libformat_json.la daemon/libmetadata.la daemon/libplugin_mock.la -lm
-endif
-
-noinst_LTLIBRARIES += liblatency.la
-liblatency_la_SOURCES = utils_latency.c utils_latency.h utils_latency_config.c utils_latency_config.h
-liblatency_la_LIBADD = daemon/libcommon.la -lm
-check_PROGRAMS += test_utils_latency
-TESTS += test_utils_latency
-test_utils_latency_SOURCES = utils_latency_test.c testing.h
-test_utils_latency_LDADD = liblatency.la daemon/libplugin_mock.la -lm
-
-noinst_LTLIBRARIES += libcmds.la
-libcmds_la_SOURCES = utils_cmds.c utils_cmds.h \
-                     utils_cmd_flush.c utils_cmd_flush.h \
-                     utils_cmd_getthreshold.c utils_cmd_getthreshold.h \
-                     utils_cmd_getval.c utils_cmd_getval.h \
-                     utils_cmd_listval.c utils_cmd_listval.h \
-                     utils_cmd_putnotif.c utils_cmd_putnotif.h \
-                     utils_cmd_putval.c utils_cmd_putval.h \
-                     utils_parse_option.c utils_parse_option.h
-libcmds_la_LIBADD = daemon/libcommon.la daemon/libmetadata.la -lm
-check_PROGRAMS += test_utils_cmds
-TESTS += test_utils_cmds
-test_utils_cmds_SOURCES = utils_cmds_test.c testing.h
-test_utils_cmds_LDADD = libcmds.la \
-                        daemon/libplugin_mock.la
-
-noinst_LTLIBRARIES += liblookup.la
-liblookup_la_SOURCES = utils_vl_lookup.c utils_vl_lookup.h
-liblookup_la_LIBADD = daemon/libavltree.la
-check_PROGRAMS += test_utils_vl_lookup
-TESTS += test_utils_vl_lookup
-test_utils_vl_lookup_SOURCES = utils_vl_lookup_test.c testing.h
-test_utils_vl_lookup_LDADD = liblookup.la daemon/libplugin_mock.la
-if BUILD_WITH_LIBKSTAT
-test_utils_vl_lookup_LDADD += -lkstat
-endif
-
-noinst_LTLIBRARIES += libmount.la
-libmount_la_SOURCES = utils_mount.c utils_mount.h
-check_PROGRAMS += test_utils_mount
-TESTS += test_utils_mount
-test_utils_mount_SOURCES = utils_mount_test.c testing.h
-test_utils_mount_LDADD = libmount.la daemon/libplugin_mock.la
-if BUILD_WITH_LIBKSTAT
-test_utils_mount_LDADD += -lkstat
-endif
-
-sbin_PROGRAMS = collectdmon
-bin_PROGRAMS = collectd-nagios collectdctl collectd-tg
-
-collectdmon_SOURCES = collectdmon.c
-
-collectd_nagios_SOURCES = collectd-nagios.c
-collectd_nagios_CPPFLAGS = $(AM_CPPFLAGS) \
-       -I$(top_srcdir)/src/libcollectdclient/collectd \
-       -I$(top_builddir)/src/libcollectdclient/collectd
-collectd_nagios_LDADD = libcollectdclient/libcollectdclient.la
-if BUILD_WITH_LIBSOCKET
-collectd_nagios_LDADD += -lsocket
-endif
-if BUILD_AIX
-collectd_nagios_LDADD += -lm
-endif
-
-
-collectdctl_SOURCES = collectdctl.c
-collectdctl_CPPFLAGS = $(AM_CPPFLAGS) \
-       -I$(top_srcdir)/src/libcollectdclient/collectd \
-       -I$(top_builddir)/src/libcollectdclient/collectd
-collectdctl_LDADD = libcollectdclient/libcollectdclient.la
-if BUILD_WITH_LIBSOCKET
-collectdctl_LDADD += -lsocket
-endif
-if BUILD_AIX
-collectdctl_LDADD += -lm
-endif
-
-
-collectd_tg_SOURCES = collectd-tg.c
-collectd_tg_CPPFLAGS = $(AM_CPPFLAGS) \
-       -I$(top_srcdir)/src/libcollectdclient/collectd \
-       -I$(top_builddir)/src/libcollectdclient/collectd
-collectd_tg_LDADD = \
-       $(PTHREAD_LIBS) \
-       daemon/libheap.la \
-       libcollectdclient/libcollectdclient.la
-if BUILD_WITH_LIBSOCKET
-collectd_tg_LDADD += -lsocket
-endif
-if BUILD_WITH_LIBRT
-collectd_tg_LDADD += -lrt
-endif
-if BUILD_AIX
-collectd_tg_LDADD += -lm
-endif
-
-
-pkglib_LTLIBRARIES =
-
-BUILT_SOURCES =
-CLEANFILES =
-
-if HAVE_PROTOC3
-if HAVE_GRPC_CPP
-BUILT_SOURCES += collectd.grpc.pb.cc collectd.pb.cc types.pb.cc
-CLEANFILES += collectd.grpc.pb.cc collectd.pb.cc types.pb.cc \
-               collectd.grpc.pb.h collectd.pb.h types.pb.h
-
-collectd.grpc.pb.cc: $(top_srcdir)/proto/collectd.proto $(top_srcdir)/proto/types.proto
-       $(V_PROTOC)@PROTOC@ -I$(top_srcdir)/proto \
-               --grpc_out=$(builddir) --plugin=protoc-gen-grpc=$(GRPC_CPP_PLUGIN) $<
-
-collectd.pb.cc: $(top_srcdir)/proto/collectd.proto $(top_srcdir)/proto/types.proto
-       $(V_PROTOC)@PROTOC@ -I$(top_srcdir)/proto --cpp_out=$(builddir) $<
-
-types.pb.cc: $(top_srcdir)/proto/types.proto
-       $(V_PROTOC)@PROTOC@ -I$(top_srcdir)/proto --cpp_out=$(builddir) $<
-endif
-endif
-
-if BUILD_PLUGIN_AGGREGATION
-pkglib_LTLIBRARIES += aggregation.la
-aggregation_la_SOURCES = aggregation.c \
-                         utils_vl_lookup.c utils_vl_lookup.h
-aggregation_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-aggregation_la_LIBADD = -lm
-endif
-
-if BUILD_PLUGIN_AMQP
-pkglib_LTLIBRARIES += amqp.la
-amqp_la_SOURCES = amqp.c
-amqp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRABBITMQ_LDFLAGS)
-amqp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRABBITMQ_CPPFLAGS)
-amqp_la_LIBADD = $(BUILD_WITH_LIBRABBITMQ_LIBS) \
-                 libcmds.la libformat_graphite.la libformat_json.la
-endif
-
-if BUILD_PLUGIN_APACHE
-pkglib_LTLIBRARIES += apache.la
-apache_la_SOURCES = apache.c
-apache_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-apache_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
-apache_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
-endif
-
-
-if BUILD_PLUGIN_APCUPS
-pkglib_LTLIBRARIES += apcups.la
-apcups_la_SOURCES = apcups.c
-apcups_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-apcups_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-apcups_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_APPLE_SENSORS
-pkglib_LTLIBRARIES += apple_sensors.la
-apple_sensors_la_SOURCES = apple_sensors.c
-apple_sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) -framework IOKit
-endif
-
-if BUILD_PLUGIN_AQUAERO
-pkglib_LTLIBRARIES += aquaero.la
-aquaero_la_SOURCES = aquaero.c
-aquaero_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBAQUAERO5_CFLAGS)
-aquaero_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBAQUAERO5_LDFLAGS)
-aquaero_la_LIBADD = -laquaero5
-endif
-
-if BUILD_PLUGIN_ASCENT
-pkglib_LTLIBRARIES += ascent.la
-ascent_la_SOURCES = ascent.c
-ascent_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-ascent_la_CFLAGS = $(AM_CFLAGS) \
-               $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
-ascent_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-endif
-
-if BUILD_PLUGIN_BAROMETER
-pkglib_LTLIBRARIES += barometer.la
-barometer_la_SOURCES = barometer.c
-barometer_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-barometer_la_LIBADD = -lm
-endif
-
-if BUILD_PLUGIN_BATTERY
-pkglib_LTLIBRARIES += battery.la
-battery_la_SOURCES = battery.c battery_statefs.c
-battery_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-if BUILD_WITH_LIBIOKIT
-battery_la_LDFLAGS += -framework IOKit
-endif
-endif
-
-if BUILD_PLUGIN_BIND
-pkglib_LTLIBRARIES += bind.la
-bind_la_SOURCES = bind.c
-bind_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-bind_la_CFLAGS = $(AM_CFLAGS) \
-                $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
-bind_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-endif
-
-if BUILD_PLUGIN_CEPH
-pkglib_LTLIBRARIES += ceph.la
-ceph_la_SOURCES = ceph.c
-ceph_la_CFLAGS = $(AM_CFLAGS)
-ceph_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
-ceph_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
-ceph_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
-endif
-
-if BUILD_PLUGIN_CGROUPS
-pkglib_LTLIBRARIES += cgroups.la
-cgroups_la_SOURCES = cgroups.c
-cgroups_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-cgroups_la_LIBADD = libmount.la
-endif
-
-if BUILD_PLUGIN_CHRONY
-pkglib_LTLIBRARIES += chrony.la
-chrony_la_SOURCES = chrony.c
-chrony_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_CONNTRACK
-pkglib_LTLIBRARIES += conntrack.la
-conntrack_la_SOURCES = conntrack.c
-conntrack_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_CONTEXTSWITCH
-pkglib_LTLIBRARIES += contextswitch.la
-contextswitch_la_SOURCES = contextswitch.c
-contextswitch_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-contextswitch_la_LIBADD =
-if BUILD_WITH_PERFSTAT
-contextswitch_la_LIBADD += -lperfstat
-endif
-endif
-
-if BUILD_PLUGIN_CPU
-pkglib_LTLIBRARIES += cpu.la
-cpu_la_SOURCES = cpu.c
-cpu_la_CFLAGS = $(AM_CFLAGS)
-cpu_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-cpu_la_LIBADD =
-if BUILD_WITH_LIBKSTAT
-cpu_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-cpu_la_LIBADD += -ldevinfo
-endif
-if BUILD_WITH_LIBSTATGRAB
-cpu_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-cpu_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-if BUILD_WITH_PERFSTAT
-cpu_la_LIBADD += -lperfstat
-endif
-endif
-
-if BUILD_PLUGIN_CPUFREQ
-pkglib_LTLIBRARIES += cpufreq.la
-cpufreq_la_SOURCES = cpufreq.c
-cpufreq_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_CPUSLEEP
-pkglib_LTLIBRARIES += cpusleep.la
-cpusleep_la_SOURCES = cpusleep.c
-cpusleep_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_CSV
-pkglib_LTLIBRARIES += csv.la
-csv_la_SOURCES = csv.c
-csv_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_CURL
-pkglib_LTLIBRARIES += curl.la
-curl_la_SOURCES = curl.c \
-                  utils_curl_stats.c utils_curl_stats.h \
-                  utils_match.c utils_match.h
-curl_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-curl_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
-curl_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) liblatency.la
-endif
-
-if BUILD_PLUGIN_CURL_JSON
-pkglib_LTLIBRARIES += curl_json.la
-curl_json_la_SOURCES = curl_json.c \
-                 utils_curl_stats.c utils_curl_stats.h
-curl_json_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
-curl_json_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
-curl_json_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
-curl_json_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBYAJL_LIBS)
-endif
-
-if BUILD_PLUGIN_CURL_XML
-pkglib_LTLIBRARIES += curl_xml.la
-curl_xml_la_SOURCES = curl_xml.c \
-                 utils_curl_stats.c utils_curl_stats.h
-curl_xml_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-curl_xml_la_CFLAGS = $(AM_CFLAGS) \
-               $(BUILD_WITH_LIBCURL_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
-curl_xml_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-endif
-
-if BUILD_PLUGIN_DBI
-pkglib_LTLIBRARIES += dbi.la
-dbi_la_SOURCES = dbi.c \
-                utils_db_query.c utils_db_query.h
-dbi_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBDBI_CPPFLAGS)
-dbi_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBDBI_LDFLAGS)
-dbi_la_LIBADD = $(BUILD_WITH_LIBDBI_LIBS)
-endif
-
-if BUILD_PLUGIN_DF
-pkglib_LTLIBRARIES += df.la
-df_la_SOURCES = df.c
-df_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-df_la_LIBADD = libmount.la
-endif
-
-if BUILD_PLUGIN_DISK
-pkglib_LTLIBRARIES += disk.la
-disk_la_SOURCES = disk.c
-disk_la_CFLAGS = $(AM_CFLAGS)
-disk_la_CPPFLAGS = $(AM_CPPFLAGS)
-disk_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-disk_la_LIBADD =
-if BUILD_WITH_LIBKSTAT
-disk_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-disk_la_LIBADD += -ldevinfo
-endif
-if BUILD_WITH_LIBIOKIT
-disk_la_LDFLAGS += -framework IOKit
-endif
-if BUILD_WITH_LIBSTATGRAB
-disk_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-disk_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-if BUILD_WITH_LIBUDEV
-disk_la_CPPFLAGS += $(BUILD_WITH_LIBUDEV_CPPFLAGS)
-disk_la_LDFLAGS += $(BUILD_WITH_LIBUDEV_LDFLAGS)
-disk_la_LIBADD += $(BUILD_WITH_LIBUDEV_LIBS)
-endif
-if BUILD_FREEBSD
-disk_la_LIBADD += -ldevstat -lgeom
-endif
-if BUILD_WITH_PERFSTAT
-disk_la_LIBADD += -lperfstat
-endif
-endif
-
-if BUILD_PLUGIN_DNS
-pkglib_LTLIBRARIES += dns.la
-dns_la_SOURCES = dns.c utils_dns.c utils_dns.h
-dns_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPCAP_CPPFLAGS)
-dns_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPCAP_LDFLAGS)
-dns_la_LIBADD = $(BUILD_WITH_LIBPCAP_LIBS)
-endif
-
-if BUILD_PLUGIN_DPDKSTAT
-pkglib_LTLIBRARIES += dpdkstat.la
-dpdkstat_la_SOURCES = dpdkstat.c
-dpdkstat_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS)
-dpdkstat_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS)
-dpdkstat_la_LIBADD = -ldpdk
-endif
-
-if BUILD_PLUGIN_DRBD
-pkglib_LTLIBRARIES += drbd.la
-drbd_la_SOURCES = drbd.c
-drbd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_EMAIL
-pkglib_LTLIBRARIES += email.la
-email_la_SOURCES = email.c
-email_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_ENTROPY
-pkglib_LTLIBRARIES += entropy.la
-entropy_la_SOURCES = entropy.c
-entropy_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_EXEC
-pkglib_LTLIBRARIES += exec.la
-exec_la_SOURCES = exec.c
-exec_la_LDFLAGS = $(PLUGIN_LDFLAGS) libcmds.la
-endif
-
-if BUILD_PLUGIN_ETHSTAT
-pkglib_LTLIBRARIES += ethstat.la
-ethstat_la_SOURCES = ethstat.c
-ethstat_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_FHCOUNT
-pkglib_LTLIBRARIES += fhcount.la
-fhcount_la_SOURCES = fhcount.c
-fhcount_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_FILECOUNT
-pkglib_LTLIBRARIES += filecount.la
-filecount_la_SOURCES = filecount.c
-filecount_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_GMOND
-pkglib_LTLIBRARIES += gmond.la
-gmond_la_SOURCES = gmond.c
-gmond_la_CPPFLAGS = $(AM_CPPFLAGS) $(GANGLIA_CPPFLAGS)
-gmond_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(GANGLIA_LDFLAGS)
-gmond_la_LIBADD = $(GANGLIA_LIBS)
-endif
-
-if BUILD_PLUGIN_GPS
-pkglib_LTLIBRARIES += gps.la
-gps_la_SOURCES = gps.c
-gps_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBGPS_CFLAGS)
-gps_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBGPS_LDFLAGS)
-gps_la_LIBADD = -lpthread $(BUILD_WITH_LIBGPS_LIBS)
-endif
-
-if BUILD_PLUGIN_GRPC
-pkglib_LTLIBRARIES += grpc.la
-grpc_la_SOURCES = grpc.cc
-nodist_grpc_la_SOURCES = collectd.grpc.pb.cc collectd.pb.cc types.pb.cc
-grpc_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBGRPCPP_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_CPPFLAGS)
-grpc_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBGRPCPP_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_LDFLAGS)
-grpc_la_LIBADD = $(BUILD_WITH_LIBGRPCPP_LIBS) $(BUILD_WITH_LIBPROTOBUF_LIBS)
-endif
-
-if BUILD_PLUGIN_HDDTEMP
-pkglib_LTLIBRARIES += hddtemp.la
-hddtemp_la_SOURCES = hddtemp.c
-hddtemp_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-hddtemp_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-hddtemp_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_HUGEPAGES
-pkglib_LTLIBRARIES += hugepages.la
-hugepages_la_SOURCES = hugepages.c
-hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_INTERFACE
-pkglib_LTLIBRARIES += interface.la
-interface_la_SOURCES = interface.c
-interface_la_CFLAGS = $(AM_CFLAGS)
-interface_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-interface_la_LIBADD =
-if BUILD_WITH_LIBSTATGRAB
-interface_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-interface_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-else
-if BUILD_WITH_LIBKSTAT
-interface_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-interface_la_LIBADD += -ldevinfo
-endif # BUILD_WITH_LIBDEVINFO
-endif # !BUILD_WITH_LIBSTATGRAB
-if BUILD_WITH_PERFSTAT
-interface_la_LIBADD += -lperfstat
-endif
-endif # BUILD_PLUGIN_INTERFACE
-
-if BUILD_PLUGIN_IPC
-pkglib_LTLIBRARIES += ipc.la
-ipc_la_SOURCES = ipc.c
-ipc_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_IPTABLES
-pkglib_LTLIBRARIES += iptables.la
-iptables_la_SOURCES = iptables.c
-iptables_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBIPTC_CPPFLAGS)
-iptables_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-iptables_la_LIBADD = $(BUILD_WITH_LIBIPTC_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_IPMI
-pkglib_LTLIBRARIES += ipmi.la
-ipmi_la_SOURCES = ipmi.c
-ipmi_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_OPENIPMI_CFLAGS)
-ipmi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-ipmi_la_LIBADD = $(BUILD_WITH_OPENIPMI_LIBS)
-endif
-
-if BUILD_PLUGIN_IPVS
-pkglib_LTLIBRARIES += ipvs.la
-ipvs_la_SOURCES = ipvs.c
-ipvs_la_CFLAGS = $(AM_CFLAGS)
-if IP_VS_H_NEEDS_KERNEL_CFLAGS
-ipvs_la_CFLAGS += $(KERNEL_CFLAGS)
-endif
-ipvs_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_IRQ
-pkglib_LTLIBRARIES += irq.la
-irq_la_SOURCES = irq.c
-irq_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_JAVA
-pkglib_LTLIBRARIES += java.la
-java_la_SOURCES = java.c
-java_la_CPPFLAGS = $(AM_CPPFLAGS) $(JAVA_CPPFLAGS)
-java_la_CFLAGS = $(AM_CFLAGS) $(JAVA_CFLAGS)
-java_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(JAVA_LDFLAGS)
-java_la_LIBADD = $(JAVA_LIBS)
-endif
-
-if BUILD_PLUGIN_LOAD
-pkglib_LTLIBRARIES += load.la
-load_la_SOURCES = load.c
-load_la_CFLAGS = $(AM_CFLAGS)
-load_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-load_la_LIBADD =
-if BUILD_WITH_LIBSTATGRAB
-load_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-load_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif # BUILD_WITH_LIBSTATGRAB
-if BUILD_WITH_PERFSTAT
-load_la_LIBADD += -lperfstat
-endif
-endif # BUILD_PLUGIN_LOAD
-
-if BUILD_PLUGIN_LOGFILE
-pkglib_LTLIBRARIES += logfile.la
-logfile_la_SOURCES = logfile.c
-logfile_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_LOG_LOGSTASH
-pkglib_LTLIBRARIES += log_logstash.la
-log_logstash_la_SOURCES = log_logstash.c
-log_logstash_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
-log_logstash_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
-log_logstash_la_LIBADD = $(BUILD_WITH_LIBYAJL_LIBS)
-endif
-
-if BUILD_PLUGIN_LPAR
-pkglib_LTLIBRARIES += lpar.la
-lpar_la_SOURCES = lpar.c
-lpar_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-lpar_la_LIBADD = -lperfstat
-endif
-
-if BUILD_PLUGIN_LUA
-pkglib_LTLIBRARIES += lua.la
-lua_la_SOURCES = lua.c \
-                utils_lua.c utils_lua.h
-lua_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBLUA_CFLAGS)
-lua_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-lua_la_LIBADD = $(BUILD_WITH_LIBLUA_LIBS)
-endif
-
-if BUILD_PLUGIN_LVM
-pkglib_LTLIBRARIES += lvm.la
-lvm_la_SOURCES = lvm.c
-lvm_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLVM2APP_CPPFLAGS)
-lvm_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLVM2APP_LDFLAGS)
-lvm_la_LIBADD = $(BUILD_WITH_LIBLVM2APP_LIBS)
-endif
-
-if BUILD_PLUGIN_MADWIFI
-pkglib_LTLIBRARIES += madwifi.la
-madwifi_la_SOURCES = madwifi.c madwifi.h
-madwifi_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MATCH_EMPTY_COUNTER
-pkglib_LTLIBRARIES += match_empty_counter.la
-match_empty_counter_la_SOURCES = match_empty_counter.c
-match_empty_counter_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MATCH_HASHED
-pkglib_LTLIBRARIES += match_hashed.la
-match_hashed_la_SOURCES = match_hashed.c
-match_hashed_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MATCH_REGEX
-pkglib_LTLIBRARIES += match_regex.la
-match_regex_la_SOURCES = match_regex.c
-match_regex_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MATCH_TIMEDIFF
-pkglib_LTLIBRARIES += match_timediff.la
-match_timediff_la_SOURCES = match_timediff.c
-match_timediff_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MATCH_VALUE
-pkglib_LTLIBRARIES += match_value.la
-match_value_la_SOURCES = match_value.c
-match_value_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MBMON
-pkglib_LTLIBRARIES += mbmon.la
-mbmon_la_SOURCES = mbmon.c
-mbmon_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-mbmon_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-mbmon_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_MD
-pkglib_LTLIBRARIES += md.la
-md_la_SOURCES = md.c
-md_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MEMCACHEC
-pkglib_LTLIBRARIES += memcachec.la
-memcachec_la_SOURCES = memcachec.c \
-                       utils_match.c utils_match.h
-memcachec_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMEMCACHED_LDFLAGS)
-memcachec_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMEMCACHED_CPPFLAGS)
-memcachec_la_LIBADD = $(BUILD_WITH_LIBMEMCACHED_LIBS) liblatency.la
-endif
-
-if BUILD_PLUGIN_MEMCACHED
-pkglib_LTLIBRARIES += memcached.la
-memcached_la_SOURCES = memcached.c
-memcached_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-memcached_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-memcached_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_MEMORY
-pkglib_LTLIBRARIES += memory.la
-memory_la_SOURCES = memory.c
-memory_la_CFLAGS = $(AM_CFLAGS)
-memory_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-memory_la_LIBADD =
-if BUILD_WITH_LIBKSTAT
-memory_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-memory_la_LIBADD += -ldevinfo
-endif
-if BUILD_WITH_LIBSTATGRAB
-memory_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-memory_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-if BUILD_WITH_PERFSTAT
-memory_la_LIBADD += -lperfstat
-endif
-endif
-
-if BUILD_PLUGIN_MIC
-pkglib_LTLIBRARIES += mic.la
-mic_la_SOURCES = mic.c
-mic_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_MIC_CPPFLAGS)
-mic_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_MIC_LDFLAGS)
-mic_la_LIBADD = $(BUILD_WITH_MIC_LIBS)
-endif
-
-if BUILD_PLUGIN_MODBUS
-pkglib_LTLIBRARIES += modbus.la
-modbus_la_SOURCES = modbus.c
-modbus_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-modbus_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMODBUS_CFLAGS)
-modbus_la_LIBADD = $(BUILD_WITH_LIBMODBUS_LIBS)
-endif
-
-if BUILD_PLUGIN_MQTT
-pkglib_LTLIBRARIES += mqtt.la
-mqtt_la_SOURCES = mqtt.c
-mqtt_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMOSQUITTO_CPPFLAGS)
-mqtt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMOSQUITTO_LDFLAGS)
-mqtt_la_LIBADD = $(BUILD_WITH_LIBMOSQUITTO_LIBS)
-endif
-
-if BUILD_PLUGIN_MULTIMETER
-pkglib_LTLIBRARIES += multimeter.la
-multimeter_la_SOURCES = multimeter.c
-multimeter_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_MYSQL
-pkglib_LTLIBRARIES += mysql.la
-mysql_la_SOURCES = mysql.c
-mysql_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMYSQL_CFLAGS)
-mysql_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-mysql_la_LIBADD = $(BUILD_WITH_LIBMYSQL_LIBS)
-endif
-
-if BUILD_PLUGIN_NETAPP
-pkglib_LTLIBRARIES += netapp.la
-netapp_la_SOURCES = netapp.c
-netapp_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBNETAPP_CPPFLAGS)
-netapp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBNETAPP_LDFLAGS)
-netapp_la_LIBADD = $(LIBNETAPP_LIBS)
-endif
-
-if BUILD_PLUGIN_NETLINK
-pkglib_LTLIBRARIES += netlink.la
-netlink_la_SOURCES = netlink.c
-netlink_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-netlink_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBMNL_CFLAGS)
-netlink_la_LIBADD = $(BUILD_WITH_LIBMNL_LIBS)
-endif
-
-if BUILD_PLUGIN_NETWORK
-pkglib_LTLIBRARIES += network.la
-network_la_SOURCES = network.c network.h \
-                    utils_fbhash.c utils_fbhash.h
-network_la_CPPFLAGS = $(AM_CPPFLAGS)
-network_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-network_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-network_la_LIBADD += -lsocket
-endif
-if BUILD_WITH_LIBGCRYPT
-network_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
-network_la_LDFLAGS += $(GCRYPT_LDFLAGS)
-network_la_LIBADD += $(GCRYPT_LIBS)
-endif
-endif
-
-if BUILD_PLUGIN_NFS
-pkglib_LTLIBRARIES += nfs.la
-nfs_la_SOURCES = nfs.c
-nfs_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_FSCACHE
-pkglib_LTLIBRARIES += fscache.la
-fscache_la_SOURCES = fscache.c
-fscache_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_NGINX
-pkglib_LTLIBRARIES += nginx.la
-nginx_la_SOURCES = nginx.c
-nginx_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
-nginx_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-nginx_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS)
-endif
-
-if BUILD_PLUGIN_NOTIFY_DESKTOP
-pkglib_LTLIBRARIES += notify_desktop.la
-notify_desktop_la_SOURCES = notify_desktop.c
-notify_desktop_la_CFLAGS = $(AM_CFLAGS) $(LIBNOTIFY_CFLAGS)
-notify_desktop_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-notify_desktop_la_LIBADD = $(LIBNOTIFY_LIBS)
-endif
-
-if BUILD_PLUGIN_NOTIFY_EMAIL
-pkglib_LTLIBRARIES += notify_email.la
-notify_email_la_SOURCES = notify_email.c
-notify_email_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBESMTP_CPPFLAGS)
-notify_email_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBESMTP_LDFLAGS)
-notify_email_la_LIBADD = $(BUILD_WITH_LIBESMTP_LIBS)
-endif
-
-if BUILD_PLUGIN_NOTIFY_NAGIOS
-pkglib_LTLIBRARIES += notify_nagios.la
-notify_nagios_la_SOURCES = notify_nagios.c
-notify_nagios_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_NTPD
-pkglib_LTLIBRARIES += ntpd.la
-ntpd_la_SOURCES = ntpd.c
-ntpd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-ntpd_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-ntpd_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_NUMA
-pkglib_LTLIBRARIES += numa.la
-numa_la_SOURCES = numa.c
-numa_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_NUT
-pkglib_LTLIBRARIES += nut.la
-nut_la_SOURCES = nut.c
-nut_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBUPSCLIENT_CFLAGS)
-nut_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-nut_la_LIBADD = $(BUILD_WITH_LIBUPSCLIENT_LIBS)
-endif
-
-if BUILD_PLUGIN_OLSRD
-pkglib_LTLIBRARIES += olsrd.la
-olsrd_la_SOURCES = olsrd.c
-olsrd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-olsrd_la_LIBADD =
-if BUILD_WITH_LIBSOCKET
-olsrd_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_ONEWIRE
-pkglib_LTLIBRARIES += onewire.la
-onewire_la_SOURCES = onewire.c
-onewire_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOWCAPI_CPPFLAGS)
-onewire_la_LIBADD = $(BUILD_WITH_LIBOWCAPI_LIBS)
-onewire_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOWCAPI_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_OPENLDAP
-pkglib_LTLIBRARIES += openldap.la
-openldap_la_SOURCES = openldap.c
-openldap_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBLDAP_CPPFLAGS)
-openldap_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBLDAP_LDFLAGS)
-openldap_la_LIBADD = -lldap
-endif
-
-if BUILD_PLUGIN_OPENVPN
-pkglib_LTLIBRARIES += openvpn.la
-openvpn_la_SOURCES = openvpn.c
-openvpn_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_ORACLE
-pkglib_LTLIBRARIES += oracle.la
-oracle_la_SOURCES = oracle.c \
-       utils_db_query.c utils_db_query.h
-oracle_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_ORACLE_CPPFLAGS)
-oracle_la_LIBADD = $(BUILD_WITH_ORACLE_LIBS)
-oracle_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_PERL
-pkglib_LTLIBRARIES += perl.la
-perl_la_SOURCES = perl.c
-# Despite C99 providing the "bool" type thru stdbool.h, Perl defines its own
-# version of that type if HAS_BOOL is not defined... *sigh*
-perl_la_CPPFLAGS = $(AM_CPPFLAGS) -DHAS_BOOL=1
-# Despite off_t being 64 bit wide on 64 bit platforms, Perl insist on using
-# off64_t which is only exposed when _LARGEFILE64_SOURCE is defined... *sigh*
-# On older platforms we also need _REENTRANT. _GNU_SOURCE sets both of these.
-perl_la_CPPFLAGS += -D_GNU_SOURCE
-perl_la_CFLAGS  = $(AM_CFLAGS) \
-               $(PERL_CFLAGS) \
-               -DXS_VERSION=\"$(VERSION)\" -DVERSION=\"$(VERSION)\"
-perl_la_LDFLAGS = $(PLUGIN_LDFLAGS) \
-               $(PERL_LDFLAGS)
-perl_la_LIBADD = $(PERL_LIBS)
-endif
-
-if BUILD_PLUGIN_PF
-pkglib_LTLIBRARIES += pf.la
-pf_la_SOURCES = pf.c
-pf_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_PINBA
-pkglib_LTLIBRARIES += pinba.la
-pinba_la_SOURCES = pinba.c
-nodist_pinba_la_SOURCES = pinba.pb-c.c pinba.pb-c.h
-pinba_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_CPPFLAGS)
-pinba_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_LDFLAGS)
-pinba_la_LIBADD = $(BUILD_WITH_LIBPROTOBUF_C_LIBS)
-endif
-
-if BUILD_PLUGIN_PING
-pkglib_LTLIBRARIES += ping.la
-ping_la_SOURCES = ping.c
-ping_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBOPING_CPPFLAGS)
-ping_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBOPING_LDFLAGS)
-ping_la_LIBADD = -loping -lm
-endif
-
-if BUILD_PLUGIN_POSTGRESQL
-pkglib_LTLIBRARIES += postgresql.la
-postgresql_la_SOURCES = postgresql.c \
-                utils_db_query.c utils_db_query.h
-postgresql_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPQ_CPPFLAGS)
-postgresql_la_LDFLAGS = $(PLUGIN_LDFLAGS) \
-               $(BUILD_WITH_LIBPQ_LDFLAGS)
-postgresql_la_LIBADD = $(BUILD_WITH_LIBPQ_LIBS)
-endif
-
-if BUILD_PLUGIN_POWERDNS
-pkglib_LTLIBRARIES += powerdns.la
-powerdns_la_SOURCES = powerdns.c
-powerdns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_PYTHON
-pkglib_LTLIBRARIES += python.la
-python_la_SOURCES = python.c pyconfig.c pyvalues.c cpython.h
-python_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBPYTHON_CPPFLAGS)
-if COMPILER_IS_GCC
-python_la_CPPFLAGS += -fno-strict-aliasing -Wno-strict-aliasing
-endif
-python_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBPYTHON_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_PROCESSES
-pkglib_LTLIBRARIES += processes.la
-processes_la_SOURCES = processes.c
-processes_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-processes_la_LIBADD =
-if BUILD_WITH_LIBKVM_GETPROCS
-processes_la_LIBADD += -lkvm
-endif
-endif
-
-if BUILD_PLUGIN_PROTOCOLS
-pkglib_LTLIBRARIES += protocols.la
-protocols_la_SOURCES = protocols.c
-protocols_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_INTEL_RDT
-pkglib_LTLIBRARIES += intel_rdt.la
-intel_rdt_la_SOURCES = intel_rdt.c
-intel_rdt_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPQOS_LDFLAGS)
-intel_rdt_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBPQOS_CPPFLAGS)
-intel_rdt_la_LIBADD = $(BUILD_WITH_LIBPQOS_LIBS)
-endif
-
-if BUILD_PLUGIN_REDIS
-pkglib_LTLIBRARIES += redis.la
-redis_la_SOURCES = redis.c
-redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBHIREDIS_LDFLAGS)
-redis_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBHIREDIS_CPPFLAGS)
-redis_la_LIBADD = -lhiredis
-endif
-
-if BUILD_PLUGIN_ROUTEROS
-pkglib_LTLIBRARIES += routeros.la
-routeros_la_SOURCES = routeros.c
-routeros_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBROUTEROS_CPPFLAGS)
-routeros_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBROUTEROS_LDFLAGS)
-routeros_la_LIBADD = -lrouteros
-endif
-
-if BUILD_PLUGIN_RRDCACHED
-pkglib_LTLIBRARIES += rrdcached.la
-rrdcached_la_SOURCES = rrdcached.c utils_rrdcreate.c utils_rrdcreate.h
-rrdcached_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRRD_LDFLAGS)
-rrdcached_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
-rrdcached_la_LIBADD = $(BUILD_WITH_LIBRRD_LIBS)
-endif
-
-if BUILD_PLUGIN_RRDTOOL
-pkglib_LTLIBRARIES += rrdtool.la
-rrdtool_la_SOURCES = rrdtool.c utils_rrdcreate.c utils_rrdcreate.h
-rrdtool_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRRD_LDFLAGS)
-rrdtool_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBRRD_CFLAGS)
-rrdtool_la_LIBADD = $(BUILD_WITH_LIBRRD_LIBS)
-endif
-
-if BUILD_PLUGIN_SENSORS
-pkglib_LTLIBRARIES += sensors.la
-sensors_la_SOURCES = sensors.c
-sensors_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBSENSORS_CPPFLAGS)
-sensors_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBSENSORS_LDFLAGS)
-sensors_la_LIBADD = $(BUILD_WITH_LIBSENSORS_LIBS)
-endif
-
-if BUILD_PLUGIN_SERIAL
-pkglib_LTLIBRARIES += serial.la
-serial_la_SOURCES = serial.c
-serial_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_SIGROK
-pkglib_LTLIBRARIES += sigrok.la
-sigrok_la_SOURCES = sigrok.c
-sigrok_la_CFLAGS = $(AM_CFLAGS) $(LIBSIGROK_CFLAGS)
-sigrok_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-sigrok_la_LIBADD = $(LIBSIGROK_LIBS)
-endif
-
-if BUILD_PLUGIN_SMART
-if BUILD_WITH_LIBUDEV
-pkglib_LTLIBRARIES += smart.la
-smart_la_SOURCES = smart.c
-smart_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBATASMART_CPPFLAGS) $(BUILD_WITH_LIBUDEV_CPPFLAGS)
-smart_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBATASMART_LDFLAGS) $(BUILD_WITH_LIBUDEV_LDFLAGS)
-smart_la_LIBADD = $(BUILD_WITH_LIBATASMART_LIBS) $(BUILD_WITH_LIBUDEV_LIBS)
-endif
-endif
-
-if BUILD_PLUGIN_SNMP
-pkglib_LTLIBRARIES += snmp.la
-snmp_la_SOURCES = snmp.c
-snmp_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBNETSNMP_CPPFLAGS)
-snmp_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBNETSNMP_LDFLAGS)
-snmp_la_LIBADD = $(BUILD_WITH_LIBNETSNMP_LIBS)
-endif
-
-if BUILD_PLUGIN_STATSD
-pkglib_LTLIBRARIES += statsd.la
-statsd_la_SOURCES = statsd.c
-statsd_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-statsd_la_LIBADD = liblatency.la
-endif
-
-if BUILD_PLUGIN_SWAP
-pkglib_LTLIBRARIES += swap.la
-swap_la_SOURCES = swap.c
-swap_la_CFLAGS = $(AM_CFLAGS)
-swap_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-swap_la_LIBADD =
-if BUILD_WITH_LIBKSTAT
-swap_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-swap_la_LIBADD += -ldevinfo
-endif
-if BUILD_WITH_LIBKVM_GETSWAPINFO
-swap_la_LIBADD += -lkvm
-endif
-if BUILD_WITH_LIBSTATGRAB
-swap_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-swap_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-if BUILD_WITH_PERFSTAT
-swap_la_LIBADD += -lperfstat
-endif
-
-endif
-
-if BUILD_PLUGIN_SYSLOG
-pkglib_LTLIBRARIES += syslog.la
-syslog_la_SOURCES = syslog.c
-syslog_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TABLE
-pkglib_LTLIBRARIES += table.la
-table_la_SOURCES = table.c
-table_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TAIL
-pkglib_LTLIBRARIES += tail.la
-tail_la_SOURCES = tail.c \
-                  utils_match.c utils_match.h \
-                  utils_tail.c utils_tail.h \
-                  utils_tail_match.c utils_tail_match.h
-tail_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-tail_la_LIBADD = liblatency.la
-endif
-
-if BUILD_PLUGIN_TAIL_CSV
-pkglib_LTLIBRARIES += tail_csv.la
-tail_csv_la_SOURCES = tail_csv.c \
-                      utils_tail.c utils_tail.h
-tail_csv_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TAPE
-pkglib_LTLIBRARIES += tape.la
-tape_la_SOURCES = tape.c
-tape_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-tape_la_LIBADD = -lkstat -ldevinfo
-endif
-
-if BUILD_PLUGIN_TARGET_NOTIFICATION
-pkglib_LTLIBRARIES += target_notification.la
-target_notification_la_SOURCES = target_notification.c
-target_notification_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TARGET_REPLACE
-pkglib_LTLIBRARIES += target_replace.la
-target_replace_la_SOURCES = target_replace.c
-target_replace_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TARGET_SCALE
-pkglib_LTLIBRARIES += target_scale.la
-target_scale_la_SOURCES = target_scale.c
-target_scale_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TARGET_SET
-pkglib_LTLIBRARIES += target_set.la
-target_set_la_SOURCES = target_set.c
-target_set_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TARGET_V5UPGRADE
-pkglib_LTLIBRARIES += target_v5upgrade.la
-target_v5upgrade_la_SOURCES = target_v5upgrade.c
-target_v5upgrade_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TCPCONNS
-pkglib_LTLIBRARIES += tcpconns.la
-tcpconns_la_SOURCES = tcpconns.c
-tcpconns_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-tcpconns_la_LIBADD =
-if BUILD_WITH_LIBKVM_NLIST
-tcpconns_la_LIBADD += -lkvm
-endif
-endif
-
-if BUILD_PLUGIN_TEAMSPEAK2
-pkglib_LTLIBRARIES += teamspeak2.la
-teamspeak2_la_SOURCES = teamspeak2.c
-teamspeak2_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TED
-pkglib_LTLIBRARIES += ted.la
-ted_la_SOURCES = ted.c
-ted_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_THERMAL
-pkglib_LTLIBRARIES += thermal.la
-thermal_la_SOURCES = thermal.c
-thermal_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_THRESHOLD
-pkglib_LTLIBRARIES += threshold.la
-threshold_la_SOURCES = threshold.c
-threshold_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_TOKYOTYRANT
-pkglib_LTLIBRARIES += tokyotyrant.la
-tokyotyrant_la_SOURCES = tokyotyrant.c
-tokyotyrant_la_CPPFLAGS  = $(AM_CPPFLAGS) $(BUILD_WITH_LIBTOKYOTYRANT_CPPFLAGS)
-tokyotyrant_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBTOKYOTYRANT_LDFLAGS)
-tokyotyrant_la_LIBADD  = $(BUILD_WITH_LIBTOKYOTYRANT_LIBS)
-if BUILD_WITH_LIBSOCKET
-tokyotyrant_la_LIBADD += -lsocket
-endif
-endif
-
-if BUILD_PLUGIN_TURBOSTAT
-pkglib_LTLIBRARIES += turbostat.la
-turbostat_la_SOURCES = turbostat.c
-turbostat_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_UNIXSOCK
-pkglib_LTLIBRARIES += unixsock.la
-unixsock_la_SOURCES = unixsock.c
-unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS) libcmds.la
-endif
-
-if BUILD_PLUGIN_UPTIME
-pkglib_LTLIBRARIES += uptime.la
-uptime_la_SOURCES = uptime.c
-uptime_la_CFLAGS = $(AM_CFLAGS)
-uptime_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-uptime_la_LIBADD =
-if BUILD_WITH_LIBKSTAT
-uptime_la_LIBADD += -lkstat
-endif
-if BUILD_WITH_PERFSTAT
-uptime_la_LIBADD += -lperfstat
-endif
-endif
-
-if BUILD_PLUGIN_USERS
-pkglib_LTLIBRARIES += users.la
-users_la_SOURCES = users.c
-users_la_CFLAGS = $(AM_CFLAGS)
-users_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-users_la_LIBADD =
-if BUILD_WITH_LIBSTATGRAB
-users_la_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-users_la_LIBADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-endif
-
-if BUILD_PLUGIN_UUID
-pkglib_LTLIBRARIES += uuid.la
-uuid_la_SOURCES = uuid.c
-uuid_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_VARNISH
-pkglib_LTLIBRARIES += varnish.la
-varnish_la_SOURCES = varnish.c
-varnish_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-varnish_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBVARNISH_CFLAGS)
-varnish_la_LIBADD = $(BUILD_WITH_LIBVARNISH_LIBS)
-endif
-
-if BUILD_PLUGIN_VIRT
-pkglib_LTLIBRARIES += virt.la
-virt_la_SOURCES = virt.c
-virt_la_CFLAGS = $(AM_CFLAGS) \
-               $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
-virt_la_LIBADD = $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-virt_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-
-# TODO: enable once we support only modern libvirts which depends on libnl-3
-# the libvirt on wheezy is linked in libnl v1, and there is a small leak here,
-# triggered by the library initialization. There are no means to avoid it,
-# and libvirt switched to libnl3 anyway
-#test_plugin_virt_SOURCES = virt_test.c
-#test_plugin_virt_CPPFLAGS = $(AM_CPPFLAGS) \
-#              $(BUILD_WITH_LIBVIRT_CFLAGS) $(BUILD_WITH_LIBXML2_CFLAGS)
-#test_plugin_virt_LDFLAGS = $(PLUGIN_LDFLAGS)
-#test_plugin_virt_LDADD = daemon/libplugin_mock.la \
-#              $(BUILD_WITH_LIBVIRT_LIBS) $(BUILD_WITH_LIBXML2_LIBS)
-#check_PROGRAMS += test_plugin_virt
-#TESTS += test_plugin_virt
-endif
-
-if BUILD_PLUGIN_VMEM
-pkglib_LTLIBRARIES += vmem.la
-vmem_la_SOURCES = vmem.c
-vmem_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_VSERVER
-pkglib_LTLIBRARIES += vserver.la
-vserver_la_SOURCES = vserver.c
-vserver_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_WIRELESS
-pkglib_LTLIBRARIES += wireless.la
-wireless_la_SOURCES = wireless.c
-wireless_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_WRITE_GRAPHITE
-pkglib_LTLIBRARIES += write_graphite.la
-write_graphite_la_SOURCES = write_graphite.c
-write_graphite_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-write_graphite_la_LIBADD = libformat_graphite.la
-endif
-
-if BUILD_PLUGIN_WRITE_HTTP
-pkglib_LTLIBRARIES += write_http.la
-write_http_la_SOURCES = write_http.c \
-                       utils_format_kairosdb.c utils_format_kairosdb.h
-write_http_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-write_http_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBCURL_CFLAGS)
-write_http_la_LIBADD = $(BUILD_WITH_LIBCURL_LIBS) libformat_json.la
-endif
-
-if BUILD_PLUGIN_WRITE_KAFKA
-pkglib_LTLIBRARIES += write_kafka.la
-write_kafka_la_SOURCES = write_kafka.c \
-                         utils_crc32.c utils_crc32.h
-write_kafka_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBRDKAFKA_CPPFLAGS)
-write_kafka_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBRDKAFKA_LDFLAGS)
-write_kafka_la_LIBADD = $(BUILD_WITH_LIBRDKAFKA_LIBS) \
-                        libcmds.la libformat_graphite.la libformat_json.la
-endif
-
-if BUILD_PLUGIN_WRITE_LOG
-pkglib_LTLIBRARIES += write_log.la
-write_log_la_SOURCES = write_log.c
-write_log_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-write_log_la_LIBADD = libformat_graphite.la libformat_json.la
-endif
-
-if BUILD_PLUGIN_WRITE_MONGODB
-pkglib_LTLIBRARIES += write_mongodb.la
-write_mongodb_la_SOURCES = write_mongodb.c
-write_mongodb_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBMONGOC_CPPFLAGS)
-write_mongodb_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBMONGOC_LDFLAGS)
-write_mongodb_la_LIBADD = -lmongoc
-endif
-
-if BUILD_PLUGIN_WRITE_PROMETHEUS
-pkglib_LTLIBRARIES += write_prometheus.la
-write_prometheus_la_SOURCES = write_prometheus.c
-nodist_write_prometheus_la_SOURCES = prometheus.pb-c.c prometheus.pb-c.h
-write_prometheus_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_CPPFLAGS) $(BUILD_WITH_LIBMICROHTTPD_CPPFLAGS)
-write_prometheus_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPROTOBUF_C_LDFLAGS) $(BUILD_WITH_LIBMICROHTTPD_LDFLAGS)
-write_prometheus_la_LIBADD = $(BUILD_WITH_LIBPROTOBUF_C_LIBS) $(BUILD_WITH_LIBMICROHTTPD_LIBS)
-endif
-
-if BUILD_PLUGIN_WRITE_REDIS
-pkglib_LTLIBRARIES += write_redis.la
-write_redis_la_SOURCES = write_redis.c
-write_redis_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBHIREDIS_LDFLAGS)
-write_redis_la_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBHIREDIS_CPPFLAGS)
-write_redis_la_LIBADD = -lhiredis
-endif
-
-if BUILD_PLUGIN_WRITE_RIEMANN
-pkglib_LTLIBRARIES += write_riemann.la
-write_riemann_la_SOURCES = write_riemann.c write_riemann_threshold.c write_riemann_threshold.h
-write_riemann_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBRIEMANN_CLIENT_LIBS)
-write_riemann_la_CFLAGS = $(AM_CFLAGS) $(LIBRIEMANN_CLIENT_CFLAGS)
-endif
-
-if BUILD_PLUGIN_WRITE_SENSU
-pkglib_LTLIBRARIES += write_sensu.la
-write_sensu_la_SOURCES = write_sensu.c
-write_sensu_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_WRITE_TSDB
-pkglib_LTLIBRARIES += write_tsdb.la
-write_tsdb_la_SOURCES = write_tsdb.c
-write_tsdb_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-if BUILD_PLUGIN_XENCPU
-pkglib_LTLIBRARIES += xencpu.la
-xencpu_la_SOURCES = xencpu.c
-xencpu_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBXENCTL_CPPFLAGS)
-xencpu_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBXENCTL_LDFLAGS)
-xencpu_la_LIBADD = -lxenctrl
-endif
-
-if BUILD_PLUGIN_XMMS
-pkglib_LTLIBRARIES += xmms.la
-xmms_la_SOURCES = xmms.c
-xmms_la_CFLAGS = $(AM_CFLAGS) $(BUILD_WITH_LIBXMMS_CFLAGS)
-xmms_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-xmms_la_LIBADD = $(BUILD_WITH_LIBXMMS_LIBS)
-endif
-
-if BUILD_PLUGIN_ZFS_ARC
-pkglib_LTLIBRARIES += zfs_arc.la
-zfs_arc_la_SOURCES = zfs_arc.c
-zfs_arc_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-if BUILD_FREEBSD
-zfs_arc_la_LIBADD = -lm
-endif
-if BUILD_SOLARIS
-zfs_arc_la_LIBADD = -lkstat
-endif
-endif
-
-if BUILD_PLUGIN_ZOOKEEPER
-pkglib_LTLIBRARIES += zookeeper.la
-zookeeper_la_SOURCES = zookeeper.c
-zookeeper_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-BUILT_SOURCES += $(dist_man_MANS)
-
-if BUILD_PLUGIN_ZONE
-pkglib_LTLIBRARIES += zone.la
-zone_la_SOURCES = zone.c
-zone_la_LDFLAGS = $(PLUGIN_LDFLAGS)
-endif
-
-dist_man_MANS = collectd.1 \
-               collectd.conf.5 \
-               collectd-email.5 \
-               collectd-exec.5 \
-               collectdctl.1 \
-               collectd-java.5 \
-               collectd-lua.5 \
-               collectdmon.1 \
-               collectd-nagios.1 \
-               collectd-perl.5 \
-               collectd-python.5 \
-               collectd-snmp.5 \
-               collectd-tg.1 \
-               collectd-threshold.5 \
-               collectd-unixsock.5 \
-               types.db.5
-
-EXTRA_DIST =   collectd.conf.pod \
-               collectd-email.pod \
-               collectd-exec.pod \
-               collectdctl.pod \
-               collectd-java.pod \
-               collectd-lua.pod \
-               collectdmon.pod \
-               collectd-nagios.pod \
-               collectd-perl.pod \
-               collectd-python.pod \
-               collectd.pod \
-               collectd-snmp.pod \
-               collectd-tg.pod \
-               collectd-threshold.pod \
-               collectd-unixsock.pod \
-               postgresql_default.conf \
-               types.db \
-               types.db.pod \
-               valgrind.FreeBSD.suppress
-
-AM_V_POD2MAN_C = $(am__v_POD2MAN_C_@AM_V@)
-am__v_POD2MAN_C_ = $(am__v_POD2MAN_C_@AM_DEFAULT_V@)
-am__v_POD2MAN_C_0 = @echo "  POD2MAN " $@;
-am__v_POD2MAN_C_1 =
-
-.pod.1:
-       $(AM_V_POD2MAN_C)pod2man --release=$(VERSION) --center=$(PACKAGE) $< \
-               >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
-       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
-       then \
-               echo "$@ has some POD errors!"; false; \
-       fi
-
-.pod.5:
-       $(AM_V_POD2MAN_C)pod2man --section=5 --release=$(VERSION) --center=$(PACKAGE) $< \
-               >.pod2man.tmp.$$$$ 2>/dev/null && mv -f .pod2man.tmp.$$$$ $@ || true
-       @if grep '\<POD ERRORS\>' $@ >/dev/null 2>&1; \
-       then \
-               echo "$@ has some POD errors!"; false; \
-       fi
-
-AM_V_PROTOC_C = $(am__v_PROTOC_C_@AM_V@)
-am__v_PROTOC_C_ = $(am__v_PROTOC_C_@AM_DEFAULT_V@)
-am__v_PROTOC_C_0 = @echo "  PROTOC-C" $@;
-am__v_PROTOC_C_1 =
-
-# Protocol buffer for the "pinba" plugin.
-EXTRA_DIST += pinba.proto
-if BUILD_PLUGIN_PINBA
-CLEANFILES += pinba.pb-c.c pinba.pb-c.h
-BUILT_SOURCES += pinba.pb-c.c pinba.pb-c.h
-
-pinba.pb-c.c pinba.pb-c.h: pinba.proto
-       $(AM_V_PROTOC_C)$(PROTOC_C) -I$(srcdir) --c_out . $(srcdir)/pinba.proto
-endif
-
-# Protocol buffer for the "write_prometheus" plugin.
-if BUILD_PLUGIN_WRITE_PROMETHEUS
-CLEANFILES += prometheus.pb-c.c prometheus.pb-c.h
-BUILT_SOURCES += prometheus.pb-c.c prometheus.pb-c.h
-
-prometheus.pb-c.c prometheus.pb-c.h: $(top_srcdir)/proto/prometheus.proto
-       $(AM_V_PROTOC_C)$(PROTOC_C) -I$(top_srcdir)/proto --c_out=$(builddir) $(top_srcdir)/proto/prometheus.proto
-endif
-
-install-exec-hook:
-       $(mkinstalldirs) $(DESTDIR)$(sysconfdir)
-       if test -e $(DESTDIR)$(sysconfdir)/collectd.conf; \
-       then \
-               $(INSTALL) -m 0640 collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf.pkg-orig; \
-       else \
-               $(INSTALL) -m 0640 collectd.conf $(DESTDIR)$(sysconfdir)/collectd.conf; \
-       fi; \
-       $(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
-       $(INSTALL) -m 0644 $(srcdir)/types.db $(DESTDIR)$(pkgdatadir)/types.db;
-       $(INSTALL) -m 0644 $(srcdir)/postgresql_default.conf \
-               $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
-
-uninstall-hook:
-       rm -f $(DESTDIR)$(pkgdatadir)/types.db;
-       rm -f $(DESTDIR)$(sysconfdir)/collectd.conf
-       rm -f $(DESTDIR)$(pkgdatadir)/postgresql_default.conf;
-
-if BUILD_PLUGIN_CEPH
-test_plugin_ceph_SOURCES = ceph_test.c
-test_plugin_ceph_CPPFLAGS = $(AM_CPPFLAGS) $(BUILD_WITH_LIBYAJL_CPPFLAGS)
-test_plugin_ceph_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBYAJL_LDFLAGS)
-test_plugin_ceph_LDADD = daemon/libplugin_mock.la $(BUILD_WITH_LIBYAJL_LIBS)
-check_PROGRAMS += test_plugin_ceph
-TESTS += test_plugin_ceph
-endif
index 5c02fee..78e96b2 100644 (file)
@@ -350,10 +350,12 @@ static int sysfs_file_to_buffer(char const *dir, /* {{{ */
   ssnprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply,
             basename);
 
-  status = (int)read_file_contents(filename, buffer, buffer_size);
+  status = (int)read_file_contents(filename, buffer, buffer_size - 1);
   if (status < 0)
     return status;
 
+  buffer[status] = '\0';
+
   strstripnewline(buffer);
   return 0;
 } /* }}} int sysfs_file_to_buffer */
@@ -364,7 +366,7 @@ static int sysfs_file_to_gauge(char const *dir, /* {{{ */
                                char const *power_supply, char const *basename,
                                gauge_t *ret_value) {
   int status;
-  char buffer[32] = "";
+  char buffer[32];
 
   status =
       sysfs_file_to_buffer(dir, power_supply, basename, buffer, sizeof(buffer));
index 8c1b10d..e754fa8 100644 (file)
 #@BUILD_PLUGIN_LVM_TRUE@LoadPlugin lvm
 #@BUILD_PLUGIN_MADWIFI_TRUE@LoadPlugin madwifi
 #@BUILD_PLUGIN_MBMON_TRUE@LoadPlugin mbmon
+#@BUILD_PLUGIN_MCELOG_TRUE@LoadPlugin mcelog
 #@BUILD_PLUGIN_MD_TRUE@LoadPlugin md
 #@BUILD_PLUGIN_MEMCACHEC_TRUE@LoadPlugin memcachec
 #@BUILD_PLUGIN_MEMCACHED_TRUE@LoadPlugin memcached
 #@BUILD_PLUGIN_OPENLDAP_TRUE@LoadPlugin openldap
 #@BUILD_PLUGIN_OPENVPN_TRUE@LoadPlugin openvpn
 #@BUILD_PLUGIN_ORACLE_TRUE@LoadPlugin oracle
+#@BUILD_PLUGIN_OVS_EVENTS_TRUE@LoadPlugin ovs_events
 #@BUILD_PLUGIN_PERL_TRUE@LoadPlugin perl
 #@BUILD_PLUGIN_PINBA_TRUE@LoadPlugin pinba
 #@BUILD_PLUGIN_PING_TRUE@LoadPlugin ping
 #      Port "411"
 #</Plugin>
 
+#<Plugin mcelog>
+#      McelogClientSocket "/var/run/mcelog-client"
+#      McelogLogfile "/var/log/mcelog"
+#</Plugin>
+
 #<Plugin md>
 #      Device "/dev/md0"
 #      IgnoreSelected false
 #  </Database>
 #</Plugin>
 
+#<Plugin ovs_events>
+#  Port "6640"
+#  Address "127.0.0.1"
+#  Socket "/var/run/openvswitch/db.sock"
+#  Interfaces "br0" "veth0"
+#  SendNotification false
+#</Plugin>
+
 #<Plugin perl>
 #      IncludeDir "/my/include/path"
 #      BaseName "Collectd::Plugins"
index 6a76e45..d4aa9ef 100644 (file)
@@ -3322,6 +3322,28 @@ TCP-Port to connect to. Defaults to B<411>.
 
 =back
 
+=head2 Plugin C<mcelog>
+
+The C<mcelog plugin> uses mcelog to retrieve machine check exceptions.
+
+By default the plugin connects to B<"/var/run/mcelog-client"> to check if the
+mcelog server is running. When the server is running, the plugin will tail the
+specified logfile to retrieve machine check exception information and send a
+notification with the details from the logfile. The plugin will use the mcelog
+client protocol to retrieve memory related machine check exceptions.
+
+=over 4
+
+=item B<McelogClientSocket> I<Path>
+Connect to the mcelog client socket using the UNIX domain socket at I<Path>.
+Defaults to B<"/var/run/mcelog-client">.
+
+=item B<McelogLogfile> I<Path>
+
+The mcelog file to parse. Defaults to B<"/var/log/mcelog">.
+
+=back
+
 =head2 Plugin C<md>
 
 The C<md plugin> collects information from Linux Software-RAID devices (md).
@@ -5431,6 +5453,68 @@ refer to them from.
 
 =back
 
+=head2 Plugin C<ovs_events>
+
+The I<ovs_events> plugin monitors the link status of I<Open vSwitch> (OVS)
+connected interfaces, dispatches the values to collectd and sends the
+notification whenever the link state change occurs. This plugin uses OVS
+database to get a link state change notification.
+
+B<Synopsis:>
+
+ <Plugin "ovs_events">
+   Port 6640
+   Address "127.0.0.1"
+   Socket "/var/run/openvswitch/db.sock"
+   Interfaces "br0" "veth0"
+   SendNotification false
+ </Plugin>
+
+The plugin provides the following configuration options:
+
+=over 4
+
+=item B<Address> I<node>
+
+The address of the OVS DB server JSON-RPC interface used by the plugin. To
+enable the interface, OVS DB daemon should be running with C<--remote=ptcp:>
+option. See L<ovsdb-server(1)> for more details. The option may be either
+network hostname, IPv4 numbers-and-dots notation or IPv6 hexadecimal string
+format. Defaults to B<'localhost'>.
+
+=item B<Port> I<service>
+
+TCP-port to connect to. Either a service name or a port number may be given.
+Defaults to B<6640>.
+
+=item B<Socket> I<path>
+
+The UNIX domain socket path of OVS DB server JSON-RPC interface used by the
+plugin. To enable the interface, the OVS DB daemon should be running with
+C<--remote=punix:> option. See L<ovsdb-server(1)> for more details. If this
+option is set, B<Address> and B<Port> options are ignored.
+
+=item B<Interfaces> [I<ifname> ...]
+
+List of interface names to be monitored by this plugin. If this option is not
+specified or is empty then all OVS connected interfaces on all bridges are
+monitored.
+
+Default: empty (all interfaces on all bridges are monitored)
+
+=item B<SendNotification> I<true|false>
+
+If set to true, OVS link notifications (interface status and OVS DB connection
+terminate) are sent to collectd. Default value is false.
+
+=back
+
+B<Note:> By default, the global interval setting is used within which to
+retrieve the OVS link status. To configure a plugin-specific interval, please
+use B<Interval> option of the OVS B<LoadPlugin> block settings. For milliseconds
+simple divide the time by 1000 for example if the desired interval is 50ms, set
+interval to 0.05.
+
 =head2 Plugin C<perl>
 
 This plugin embeds a Perl-interpreter into collectd and provides an interface
@@ -8149,6 +8233,8 @@ packets.
 Synopsis:
 
  <Plugin write_tsdb>
+   ResolveInterval 60
+   ResolveJitter 60
    <Node "example">
      Host "tsd-1.my.domain"
      Port "4242"
@@ -8157,7 +8243,36 @@ Synopsis:
  </Plugin>
 
 The configuration consists of one or more E<lt>B<Node>E<nbsp>I<Name>E<gt>
-blocks. Inside the B<Node> blocks, the following options are recognized:
+blocks and global directives.
+
+Global directives are:
+
+=over 4
+
+=item B<ResolveInterval> I<seconds>
+
+=item B<ResolveJitter> I<seconds>
+
+When I<collectd> connects to a TSDB node, it will request the hostname from
+DNS. This can become a problem if the TSDB node is unavailable or badly
+configured because collectd will request DNS in order to reconnect for every
+metric, which can flood your DNS. So you can cache the last value for
+I<ResolveInterval> seconds.
+Defaults to the I<Interval> of the I<write_tsdb plugin>, e.g. 10E<nbsp>seconds.
+
+You can also define a jitter, a random interval to wait in addition to
+I<ResolveInterval>. This prevents all your collectd servers to resolve the
+hostname at the same time when the connection fails.
+Defaults to the I<Interval> of the I<write_tsdb plugin>, e.g. 10E<nbsp>seconds.
+
+B<Note:> If the DNS resolution has already been successful when the socket
+closes, the plugin will try to reconnect immediately with the cached
+information. DNS is queried only when the socket is closed for a longer than
+I<ResolveInterval> + I<ResolveJitter> seconds.
+
+=back
+
+Inside the B<Node> blocks, the following options are recognized:
 
 =over 4
 
diff --git a/src/daemon/Makefile.am b/src/daemon/Makefile.am
deleted file mode 100644 (file)
index 9a0ba8f..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-AM_CPPFLAGS = -I$(top_srcdir)/src
-AM_CPPFLAGS += -DPREFIX='"${prefix}"'
-AM_CPPFLAGS += -DCONFIGFILE='"${sysconfdir}/${PACKAGE_NAME}.conf"'
-AM_CPPFLAGS += -DLOCALSTATEDIR='"${localstatedir}"'
-AM_CPPFLAGS += -DPKGLOCALSTATEDIR='"${localstatedir}/lib/${PACKAGE_NAME}"'
-if BUILD_FEATURE_DAEMON
-AM_CPPFLAGS += -DPIDFILE='"${localstatedir}/run/${PACKAGE_NAME}.pid"'
-endif
-AM_CPPFLAGS += -DPLUGINDIR='"${pkglibdir}"'
-AM_CPPFLAGS += -DPKGDATADIR='"${pkgdatadir}"'
-
-# Link to these libraries..
-COMMON_LIBS = $(PTHREAD_LIBS)
-if BUILD_WITH_CAPABILITY
-COMMON_LIBS += -lcap
-endif
-if BUILD_WITH_LIBRT
-COMMON_LIBS += -lrt
-endif
-if BUILD_WITH_LIBPOSIX4
-COMMON_LIBS += -lposix4
-endif
-if BUILD_WITH_LIBSOCKET
-COMMON_LIBS += -lsocket
-endif
-if BUILD_WITH_LIBKSTAT
-COMMON_LIBS += -lkstat
-endif
-if BUILD_WITH_LIBDEVINFO
-COMMON_LIBS += -ldevinfo
-endif
-
-sbin_PROGRAMS = collectd
-
-noinst_LTLIBRARIES = libavltree.la libcommon.la libheap.la libmetadata.la libplugin_mock.la
-
-libavltree_la_SOURCES = utils_avltree.c utils_avltree.h
-
-libcommon_la_SOURCES = common.c common.h
-libcommon_la_LIBADD = $(COMMON_LIBS)
-
-libheap_la_SOURCES = utils_heap.c utils_heap.h
-
-libmetadata_la_SOURCES = meta_data.c meta_data.h
-
-libplugin_mock_la_SOURCES = plugin_mock.c utils_cache_mock.c \
-                           utils_complain.c utils_complain.h \
-                           utils_ignorelist.c utils_ignorelist.h \
-                           utils_time.c utils_time.h
-libplugin_mock_la_CPPFLAGS = $(AM_CPPFLAGS) -DMOCK_TIME
-libplugin_mock_la_LIBADD = $(COMMON_LIBS) libcommon.la
-
-collectd_SOURCES = collectd.c collectd.h \
-                  configfile.c configfile.h \
-                  filter_chain.c filter_chain.h \
-                  meta_data.c meta_data.h \
-                  plugin.c plugin.h \
-                  utils_cache.c utils_cache.h \
-                  utils_complain.c utils_complain.h \
-                  utils_ignorelist.c utils_ignorelist.h \
-                  utils_llist.c utils_llist.h \
-                  utils_random.c utils_random.h \
-                  utils_subst.c utils_subst.h \
-                  utils_time.c utils_time.h \
-                  types_list.c types_list.h \
-                  utils_threshold.c utils_threshold.h
-
-
-collectd_CFLAGS = $(AM_CFLAGS)
-collectd_LDFLAGS = -export-dynamic
-collectd_LDADD = libavltree.la libcommon.la libheap.la -lm $(COMMON_LIBS) $(DLOPEN_LIBS)
-collectd_DEPENDENCIES = libavltree.la libcommon.la libheap.la libmetadata.la
-
-# The daemon needs to call sg_init, so we need to link it against libstatgrab,
-# too. -octo
-if BUILD_WITH_LIBSTATGRAB
-collectd_CFLAGS += $(BUILD_WITH_LIBSTATGRAB_CFLAGS)
-collectd_LDADD += $(BUILD_WITH_LIBSTATGRAB_LDFLAGS)
-endif
-
-collectd_LDADD += $(top_builddir)/src/liboconfig/liboconfig.la
-collectd_DEPENDENCIES += $(top_builddir)/src/liboconfig/liboconfig.la
-
-LOG_COMPILER = env VALGRIND="@VALGRIND@" $(abs_top_srcdir)/testwrapper.sh
-
-check_PROGRAMS = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_time test_utils_subst
-TESTS          = test_common test_meta_data test_utils_avltree test_utils_heap test_utils_time test_utils_subst
-
-test_common_SOURCES = common_test.c ../testing.h
-test_common_LDADD = libplugin_mock.la
-
-test_meta_data_SOURCES = meta_data_test.c ../testing.h
-test_meta_data_LDADD = libmetadata.la libplugin_mock.la
-
-test_utils_avltree_SOURCES = utils_avltree_test.c ../testing.h
-test_utils_avltree_LDADD = libavltree.la $(COMMON_LIBS)
-
-test_utils_heap_SOURCES = utils_heap_test.c ../testing.h
-test_utils_heap_LDADD = libheap.la $(COMMON_LIBS)
-
-test_utils_time_SOURCES = utils_time_test.c ../testing.h
-
-test_utils_subst_SOURCES = utils_subst_test.c ../testing.h \
-                          utils_subst.c utils_subst.h
-test_utils_subst_LDADD = libplugin_mock.la
index 40822d0..64dbee6 100644 (file)
@@ -267,8 +267,10 @@ ssize_t swrite(int fd, const void *buf, size_t count) {
   ptr = (const char *)buf;
   nleft = count;
 
-  if (fd < 0)
-    return (-1);
+  if (fd < 0) {
+    errno = EINVAL;
+    return errno;
+  }
 
   /* checking for closed peer connection */
   pfd.fd = fd;
@@ -277,10 +279,9 @@ ssize_t swrite(int fd, const void *buf, size_t count) {
   if (poll(&pfd, 1, 0) > 0) {
     char buffer[32];
     if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) {
-      // if recv returns zero (even though poll() said there is data to be
-      // read),
-      // that means the connection has been closed
-      return -1;
+      /* if recv returns zero (even though poll() said there is data to be
+       * read), that means the connection has been closed */
+      return errno ? errno : -1;
     }
   }
 
@@ -291,7 +292,7 @@ ssize_t swrite(int fd, const void *buf, size_t count) {
       continue;
 
     if (status < 0)
-      return (status);
+      return errno ? errno : status;
 
     nleft = nleft - ((size_t)status);
     ptr = ptr + ((size_t)status);
index b57aadc..654cc49 100644 (file)
@@ -1119,14 +1119,36 @@ int cf_util_get_boolean(const oconfig_item_t *ci, _Bool *ret_bool) /* {{{ */
   if ((ci == NULL) || (ret_bool == NULL))
     return (EINVAL);
 
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN)) {
+  if ((ci->values_num != 1) || ((ci->values[0].type != OCONFIG_TYPE_BOOLEAN) &&
+                                (ci->values[0].type != OCONFIG_TYPE_STRING))) {
     ERROR("cf_util_get_boolean: The %s option requires "
           "exactly one boolean argument.",
           ci->key);
     return (-1);
   }
 
-  *ret_bool = ci->values[0].value.boolean ? 1 : 0;
+  switch (ci->values[0].type) {
+  case OCONFIG_TYPE_BOOLEAN:
+    *ret_bool = ci->values[0].value.boolean ? 1 : 0;
+    break;
+  case OCONFIG_TYPE_STRING:
+    WARNING("cf_util_get_boolean: Using string value `%s' for boolean option "
+            "`%s' is deprecated and will be removed in future releases. "
+            "Use unquoted true or false instead.",
+            ci->values[0].value.string, ci->key);
+
+    if (IS_TRUE(ci->values[0].value.string))
+      *ret_bool = 1;
+    else if (IS_FALSE(ci->values[0].value.string))
+      *ret_bool = 0;
+    else {
+      ERROR("cf_util_get_boolean: Cannot parse string value `%s' of the `%s' "
+            "option as a boolean value.",
+            ci->values[0].value.string, ci->key);
+      return (-1);
+    }
+    break;
+  }
 
   return (0);
 } /* }}} int cf_util_get_boolean */
index d490986..77b500f 100644 (file)
@@ -50,7 +50,7 @@ static void cdrand_seed(void) {
   have_seed = 1;
 }
 
-double cdrand_d() {
+double cdrand_d(void) {
   double r;
 
   pthread_mutex_lock(&lock);
@@ -61,7 +61,7 @@ double cdrand_d() {
   return (r);
 }
 
-uint32_t cdrand_u() {
+uint32_t cdrand_u(void) {
   long r;
 
   pthread_mutex_lock(&lock);
index e25ae9b..75bdc12 100644 (file)
@@ -29,7 +29,7 @@
  *
  * This function is thread- and reentrant-safe.
  */
-double cdrand_d();
+double cdrand_d(void);
 
 /**
  * cdrand_u returns a random uint32_t value uniformly distributed in the range
@@ -37,7 +37,7 @@ double cdrand_d();
  *
  * This function is thread- and reentrant-safe.
  */
-uint32_t cdrand_u();
+uint32_t cdrand_u(void);
 
 /**
  * Returns a random long between min and max, inclusively.
index de75c0c..d138345 100644 (file)
@@ -159,8 +159,8 @@ static int dpdk_shm_init(size_t size);
 static void dpdk_config_init_default(void) {
   g_configuration->interval = plugin_get_interval();
   if (g_configuration->interval == cf_get_default_interval())
-    WARNING("dpdkstat: No time interval was configured, default value %lu ms "
-            "is set",
+    WARNING("dpdkstat: No time interval was configured, default value %" PRIu64
+            " ms is set",
             CDTIME_T_TO_MS(g_configuration->interval));
   /* Default is all ports enabled */
   g_configuration->enabled_port_mask = ~0;
@@ -289,13 +289,13 @@ static int dpdk_shm_init(size_t size) {
   if (err) {
     ERROR("dpdkstat semaphore init failed: %s",
           sstrerror(errno, errbuf, sizeof(errbuf)));
-    goto fail_close;
+    goto fail;
   }
   err = sem_init(&g_configuration->sema_stats_in_shm, 1, 0);
   if (err) {
     ERROR("dpdkstat semaphore init failed: %s",
           sstrerror(errno, errbuf, sizeof(errbuf)));
-    goto fail_close;
+    goto fail;
   }
 
   g_configuration->xstats = NULL;
@@ -413,7 +413,7 @@ static int dpdk_helper_spawn(enum DPDK_HELPER_ACTION action) {
   if (pid > 0) {
     close(g_configuration->helper_pipes[1]);
     g_configuration->helper_pid = pid;
-    DEBUG("dpdkstat: helper pid %lu", (long)g_configuration->helper_pid);
+    DEBUG("dpdkstat: helper pid %li", (long)g_configuration->helper_pid);
     /* Kick helper once its alive to have it start processing */
     sem_post(&g_configuration->sema_helper_get_stats);
   } else if (pid == 0) {
index 08d5729..72a8d6e 100644 (file)
@@ -361,8 +361,6 @@ static void *collect(void *arg) {
 } /* static void *collect (void *) */
 
 static void *open_connection(void __attribute__((unused)) * arg) {
-  struct sockaddr_un addr;
-
   const char *path = (NULL == sock_file) ? SOCK_PATH : sock_file;
   const char *group = (NULL == sock_group) ? COLLECTD_GRP_NAME : sock_group;
 
@@ -375,7 +373,9 @@ static void *open_connection(void __attribute__((unused)) * arg) {
     pthread_exit((void *)1);
   }
 
-  addr.sun_family = AF_UNIX;
+  struct sockaddr_un addr = {
+    .sun_family = AF_UNIX
+  };
   sstrncpy(addr.sun_path, path, (size_t)(UNIX_PATH_MAX - 1));
 
   errno = 0;
diff --git a/src/libcollectdclient/Makefile.am b/src/libcollectdclient/Makefile.am
deleted file mode 100644 (file)
index e81a594..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-AUTOMAKE_OPTIONS = foreign no-dependencies
-
-pkginclude_HEADERS = collectd/client.h collectd/network.h collectd/network_buffer.h collectd/lcc_features.h
-lib_LTLIBRARIES = libcollectdclient.la
-nodist_pkgconfig_DATA = libcollectdclient.pc
-
-BUILT_SOURCES = collectd/lcc_features.h
-
-libcollectdclient_la_SOURCES = client.c network.c network_buffer.c
-libcollectdclient_la_CPPFLAGS = $(AM_CPPFLAGS) \
-                               -I$(top_srcdir)/src/libcollectdclient/collectd \
-                               -I$(top_builddir)/src/libcollectdclient/collectd \
-                               -I$(top_srcdir)/src/daemon
-libcollectdclient_la_LDFLAGS = -version-info 1:0:0
-libcollectdclient_la_LIBADD = 
-if BUILD_WITH_LIBGCRYPT
-libcollectdclient_la_CPPFLAGS += $(GCRYPT_CPPFLAGS)
-libcollectdclient_la_LDFLAGS += $(GCRYPT_LDFLAGS)
-libcollectdclient_la_LIBADD += $(GCRYPT_LIBS)
-endif
diff --git a/src/liboconfig/Makefile.am b/src/liboconfig/Makefile.am
deleted file mode 100644 (file)
index 5ac0ef3..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-BUILT_SOURCES = parser.h
-#CLEANFILES = parser.[ch] scanner.c
-AM_YFLAGS = -d
-
-noinst_LTLIBRARIES = liboconfig.la
-
-liboconfig_la_LDFLAGS = -avoid-version $(LEXLIB)
-liboconfig_la_SOURCES = oconfig.c oconfig.h aux_types.h scanner.l parser.y
diff --git a/src/mcelog.c b/src/mcelog.c
new file mode 100644 (file)
index 0000000..6dbfafc
--- /dev/null
@@ -0,0 +1,512 @@
+/*-
+ * collectd - src/mcelog.c
+ * MIT License
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+
+ * Authors:
+ *   Maryam Tahhan <maryam.tahhan@intel.com>
+ *   Volodymyr Mytnyk <volodymyrx.mytnyk@intel.com>
+ *   Taras Chornyi <tarasx.chornyi@intel.com>
+ *   Krzysztof Matczak <krzysztofx.matczak@intel.com>
+ */
+
+#include "common.h"
+#include "collectd.h"
+
+#include <poll.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#define MCELOG_PLUGIN "mcelog"
+#define MCELOG_BUFF_SIZE 1024
+#define MCELOG_POLL_TIMEOUT 1000 /* ms */
+#define MCELOG_SOCKET_STR "SOCKET"
+#define MCELOG_DIMM_NAME "DMI_NAME"
+#define MCELOG_CORRECTED_ERR "corrected memory errors:"
+#define MCELOG_UNCORRECTED_ERR "uncorrected memory errors:"
+
+typedef struct mcelog_config_s {
+  char logfile[PATH_MAX]; /* mcelog logfile */
+  pthread_t tid;          /* poll thread id */
+} mcelog_config_t;
+
+typedef struct socket_adapter_s socket_adapter_t;
+
+struct socket_adapter_s {
+  int sock_fd;                  /* mcelog server socket fd */
+  struct sockaddr_un unix_sock; /* mcelog client socket */
+  pthread_rwlock_t lock;
+  /* function pointers for socket operations */
+  int (*write)(socket_adapter_t *self, const char *msg, const size_t len);
+  int (*reinit)(socket_adapter_t *self);
+  int (*receive)(socket_adapter_t *self, FILE **p_file);
+  int (*close)(socket_adapter_t *self);
+};
+
+typedef struct mcelog_memory_rec_s {
+  int corrected_err_total;           /* x total*/
+  int corrected_err_timed;           /* x in 24h*/
+  char corrected_err_timed_period[DATA_MAX_NAME_LEN];
+  int uncorrected_err_total; /* x total*/
+  int uncorrected_err_timed; /* x in 24h*/
+  char uncorrected_err_timed_period[DATA_MAX_NAME_LEN];
+  char location[DATA_MAX_NAME_LEN];  /* SOCKET x CHANNEL x DIMM x*/
+  char dimm_name[DATA_MAX_NAME_LEN]; /* DMI_NAME "DIMM_F1" */
+} mcelog_memory_rec_t;
+
+static int socket_close(socket_adapter_t *self);
+static int socket_write(socket_adapter_t *self, const char *msg,
+                        const size_t len);
+static int socket_reinit(socket_adapter_t *self);
+static int socket_receive(socket_adapter_t *self, FILE **p_file);
+
+static mcelog_config_t g_mcelog_config = {
+    .logfile = "/var/log/mcelog", .tid = 0,
+};
+
+static socket_adapter_t socket_adapter = {
+    .sock_fd = -1,
+    .unix_sock =
+        {
+            .sun_family = AF_UNIX, .sun_path = "/var/run/mcelog-client",
+        },
+    .lock = PTHREAD_RWLOCK_INITIALIZER,
+    .close = socket_close,
+    .write = socket_write,
+    .reinit = socket_reinit,
+    .receive = socket_receive,
+};
+
+static _Bool mcelog_thread_running = 0;
+
+static int mcelog_config(oconfig_item_t *ci) {
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+    if (strcasecmp("McelogClientSocket", child->key) == 0) {
+      if (cf_util_get_string_buffer(child, socket_adapter.unix_sock.sun_path,
+                                    sizeof(socket_adapter.unix_sock.sun_path)) <
+          0) {
+        ERROR("%s: Invalid configuration option: \"%s\".", MCELOG_PLUGIN,
+              child->key);
+        return -1;
+      }
+    } else if (strcasecmp("McelogLogfile", child->key) == 0) {
+      if (cf_util_get_string_buffer(child, g_mcelog_config.logfile,
+                                    sizeof(g_mcelog_config.logfile)) < 0) {
+        ERROR("%s: Invalid configuration option: \"%s\".", MCELOG_PLUGIN,
+              child->key);
+        return -1;
+      }
+    } else {
+      ERROR("%s: Invalid configuration option: \"%s\".", MCELOG_PLUGIN,
+            child->key);
+      return -1;
+    }
+  }
+  return (0);
+}
+
+static int socket_close(socket_adapter_t *self) {
+  int ret = 0;
+  pthread_rwlock_rdlock(&self->lock);
+  if (fcntl(self->sock_fd, F_GETFL) != -1) {
+    if (shutdown(self->sock_fd, SHUT_RDWR) != 0) {
+      char errbuf[MCELOG_BUFF_SIZE];
+      ERROR("%s: Socket shutdown failed: %s", MCELOG_PLUGIN,
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+      ret = -1;
+    }
+    close(self->sock_fd);
+  }
+  pthread_rwlock_unlock(&self->lock);
+  return ret;
+}
+
+static int socket_write(socket_adapter_t *self, const char *msg,
+                        const size_t len) {
+  int ret = 0;
+  pthread_rwlock_rdlock(&self->lock);
+  if (swrite(self->sock_fd, msg, len) < 0)
+    ret = -1;
+  pthread_rwlock_unlock(&self->lock);
+  return ret;
+}
+
+static int socket_reinit(socket_adapter_t *self) {
+  char errbuff[MCELOG_BUFF_SIZE];
+  int ret = -1;
+  cdtime_t interval = plugin_get_interval();
+  struct timeval socket_timeout = CDTIME_T_TO_TIMEVAL(interval);
+
+  /* synchronization via write lock since sock_fd may be changed here */
+  pthread_rwlock_wrlock(&self->lock);
+  self->sock_fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+  if (self->sock_fd < 0) {
+    ERROR("%s: Could not create a socket. %s", MCELOG_PLUGIN,
+          sstrerror(errno, errbuff, sizeof(errbuff)));
+    pthread_rwlock_unlock(&self->lock);
+    return ret;
+  }
+
+  /* Set socket timeout option */
+  if (setsockopt(self->sock_fd, SOL_SOCKET, SO_SNDTIMEO,
+                 &socket_timeout, sizeof(socket_timeout)) < 0)
+    ERROR("%s: Failed to set the socket timeout option.", MCELOG_PLUGIN);
+
+  /* downgrading to read lock due to possible recursive read locks
+   * in self->close(self) call */
+  pthread_rwlock_unlock(&self->lock);
+  pthread_rwlock_rdlock(&self->lock);
+  if (connect(self->sock_fd, (struct sockaddr *)&(self->unix_sock),
+              sizeof(self->unix_sock)) < 0) {
+    ERROR("%s: Failed to connect to mcelog server. %s", MCELOG_PLUGIN,
+          sstrerror(errno, errbuff, sizeof(errbuff)));
+    self->close(self);
+    ret = -1;
+  } else
+    ret = 0;
+
+  pthread_rwlock_unlock(&self->lock);
+  return ret;
+}
+
+static void mcelog_dispatch_notification(notification_t n) {
+  sstrncpy(n.host, hostname_g, sizeof(n.host));
+  sstrncpy(n.type, "gauge", sizeof(n.type));
+  plugin_dispatch_notification(&n);
+}
+
+static int mcelog_prepare_notification(notification_t *n,
+                                       mcelog_memory_rec_t mr) {
+  if (n == NULL)
+    return (-1);
+
+  if (plugin_notification_meta_add_string(n, MCELOG_SOCKET_STR, mr.location) <
+      0) {
+    ERROR("%s: add memory location meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (strlen(mr.dimm_name) > 0)
+    if (plugin_notification_meta_add_string(n, MCELOG_DIMM_NAME, mr.dimm_name) <
+        0) {
+      ERROR("%s: add DIMM name meta data failed", MCELOG_PLUGIN);
+      return (-1);
+    }
+  if (plugin_notification_meta_add_signed_int(n, MCELOG_CORRECTED_ERR,
+                                              mr.corrected_err_total) < 0) {
+    ERROR("%s: add corrected errors meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (plugin_notification_meta_add_signed_int(
+          n, "corrected memory timed errors", mr.corrected_err_timed) < 0) {
+    ERROR("%s: add corrected timed errors meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (plugin_notification_meta_add_string(n, "corrected errors time period",
+                                          mr.corrected_err_timed_period) < 0) {
+    ERROR("%s: add corrected errors period meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (plugin_notification_meta_add_signed_int(n, MCELOG_UNCORRECTED_ERR,
+                                              mr.uncorrected_err_total) < 0) {
+    ERROR("%s: add corrected errors meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (plugin_notification_meta_add_signed_int(
+          n, "uncorrected memory timed errors", mr.uncorrected_err_timed) < 0) {
+    ERROR("%s: add corrected timed errors meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+  if (plugin_notification_meta_add_string(n, "uncorrected errors time period",
+                                          mr.uncorrected_err_timed_period) <
+      0) {
+    ERROR("%s: add corrected errors period meta data failed", MCELOG_PLUGIN);
+    return (-1);
+  }
+
+  return (0);
+}
+
+static int mcelog_submit(mcelog_memory_rec_t mr) {
+
+  value_list_t vl = VALUE_LIST_INIT;
+  vl.values_len = 1;
+  vl.time = cdtime();
+
+  sstrncpy(vl.plugin, MCELOG_PLUGIN, sizeof(vl.plugin));
+  sstrncpy(vl.type, "errors", sizeof(vl.type));
+  if (strlen(mr.dimm_name) > 0) {
+    ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s_%s",
+              mr.location, mr.dimm_name);
+  } else
+    sstrncpy(vl.plugin_instance, mr.location, sizeof(vl.plugin_instance));
+
+  sstrncpy(vl.type_instance, "corrected_memory_errors",
+           sizeof(vl.type_instance));
+  vl.values = &(value_t){.derive = (derive_t)mr.corrected_err_total};
+  plugin_dispatch_values(&vl);
+
+  ssnprintf(vl.type_instance, sizeof(vl.type_instance),
+            "corrected_memory_errors_in_%s", mr.corrected_err_timed_period);
+  vl.values = &(value_t){.derive = (derive_t)mr.corrected_err_timed};
+  plugin_dispatch_values(&vl);
+
+  sstrncpy(vl.type_instance, "uncorrected_memory_errors",
+           sizeof(vl.type_instance));
+  vl.values = &(value_t){.derive = (derive_t)mr.uncorrected_err_total};
+  plugin_dispatch_values(&vl);
+
+  ssnprintf(vl.type_instance, sizeof(vl.type_instance),
+            "uncorrected_memory_errors_in_%s", mr.uncorrected_err_timed_period);
+  vl.values = &(value_t){.derive = (derive_t)mr.uncorrected_err_timed};
+  plugin_dispatch_values(&vl);
+
+  return 0;
+}
+
+static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) {
+  char buf[DATA_MAX_NAME_LEN] = {0};
+  while (fgets(buf, sizeof(buf), p_file)) {
+    /* Got empty line or "done" */
+    if ((!strncmp("\n", buf, strlen(buf))) ||
+        (!strncmp(buf, "done\n", strlen(buf))))
+      return 1;
+    if (strlen(buf) < 5)
+      continue;
+    if (!strncmp(buf, MCELOG_SOCKET_STR, strlen(MCELOG_SOCKET_STR))) {
+      sstrncpy(memory_record->location, buf, strlen(buf));
+      /* replace spaces with '_' */
+      for (size_t i = 0; i < strlen(memory_record->location); i++)
+        if (memory_record->location[i] == ' ')
+          memory_record->location[i] = '_';
+      DEBUG("%s: Got SOCKET INFO %s", MCELOG_PLUGIN, memory_record->location);
+    }
+    if (!strncmp(buf, MCELOG_DIMM_NAME, strlen(MCELOG_DIMM_NAME))) {
+      char *name = NULL;
+      char *saveptr = NULL;
+      name = strtok_r(buf, "\"", &saveptr);
+      if (name != NULL && saveptr != NULL) {
+        name = strtok_r(NULL, "\"", &saveptr);
+        if (name != NULL) {
+          sstrncpy(memory_record->dimm_name, name,
+                   sizeof(memory_record->dimm_name));
+          DEBUG("%s: Got DIMM NAME %s", MCELOG_PLUGIN,
+                memory_record->dimm_name);
+        }
+      }
+    }
+    if (!strncmp(buf, MCELOG_CORRECTED_ERR, strlen(MCELOG_CORRECTED_ERR))) {
+      /* Get next line*/
+      if (fgets(buf, sizeof(buf), p_file) != NULL) {
+        sscanf(buf, "\t%d total", &(memory_record->corrected_err_total));
+        DEBUG("%s: Got corrected error total %d", MCELOG_PLUGIN,
+              memory_record->corrected_err_total);
+      }
+      if (fgets(buf, sizeof(buf), p_file) != NULL) {
+        sscanf(buf, "\t%d in %s", &(memory_record->corrected_err_timed),
+               memory_record->corrected_err_timed_period);
+        DEBUG("%s: Got timed corrected errors %d in %s", MCELOG_PLUGIN,
+              memory_record->corrected_err_total,
+              memory_record->corrected_err_timed_period);
+      }
+    }
+    if (!strncmp(buf, MCELOG_UNCORRECTED_ERR, strlen(MCELOG_UNCORRECTED_ERR))) {
+      if (fgets(buf, sizeof(buf), p_file) != NULL) {
+        sscanf(buf, "\t%d total", &(memory_record->uncorrected_err_total));
+        DEBUG("%s: Got uncorrected error total %d", MCELOG_PLUGIN,
+              memory_record->uncorrected_err_total);
+      }
+      if (fgets(buf, sizeof(buf), p_file) != NULL) {
+        sscanf(buf, "\t%d in %s", &(memory_record->uncorrected_err_timed),
+               memory_record->uncorrected_err_timed_period);
+        DEBUG("%s: Got timed uncorrected errors %d in %s", MCELOG_PLUGIN,
+              memory_record->uncorrected_err_total,
+              memory_record->uncorrected_err_timed_period);
+      }
+    }
+    memset(buf, 0, sizeof(buf));
+  }
+  /* parsing definitely finished */
+  return 0;
+}
+
+static void poll_worker_cleanup(void *arg) {
+  mcelog_thread_running = 0;
+  FILE *p_file = *((FILE **)arg);
+  if (p_file != NULL)
+    fclose(p_file);
+  free(arg);
+}
+
+static int socket_receive(socket_adapter_t *self, FILE **pp_file) {
+  int res = -1;
+  pthread_rwlock_rdlock(&self->lock);
+  struct pollfd poll_fd = {
+      .fd = self->sock_fd, .events = POLLIN | POLLPRI,
+  };
+
+  if ((res = poll(&poll_fd, 1, MCELOG_POLL_TIMEOUT)) <= 0) {
+    if (res != 0 && errno != EINTR) {
+      char errbuf[MCELOG_BUFF_SIZE];
+      ERROR("mcelog: poll failed: %s",
+            sstrerror(errno, errbuf, sizeof(errbuf)));
+    }
+    pthread_rwlock_unlock(&self->lock);
+    return res;
+  }
+
+  if (poll_fd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+    /* connection is broken */
+    ERROR("%s: Connection to socket is broken", MCELOG_PLUGIN);
+    if (poll_fd.revents & (POLLERR | POLLHUP)) {
+      notification_t n = {
+          NOTIF_FAILURE, cdtime(), "", "", MCELOG_PLUGIN, "", "", "", NULL};
+      ssnprintf(n.message, sizeof(n.message),
+                "Connection to mcelog socket is broken.");
+      sstrncpy(n.type_instance, "mcelog_status", sizeof(n.type_instance));
+      mcelog_dispatch_notification(n);
+    }
+    pthread_rwlock_unlock(&self->lock);
+    return -1;
+  }
+
+  if (!(poll_fd.revents & (POLLIN | POLLPRI))) {
+    INFO("%s: No data to read", MCELOG_PLUGIN);
+    pthread_rwlock_unlock(&self->lock);
+    return 0;
+  }
+
+  if ((*pp_file = fdopen(dup(self->sock_fd), "r")) == NULL)
+    res = -1;
+
+  pthread_rwlock_unlock(&self->lock);
+  return res;
+}
+
+static void *poll_worker(__attribute__((unused)) void *arg) {
+  char errbuf[MCELOG_BUFF_SIZE];
+  mcelog_thread_running = 1;
+  FILE **pp_file = calloc(1, sizeof(*pp_file));
+  if (pp_file == NULL) {
+    ERROR("mcelog: memory allocation failed: %s",
+          sstrerror(errno, errbuf, sizeof(errbuf)));
+    pthread_exit((void *)1);
+  }
+
+  pthread_cleanup_push(poll_worker_cleanup, pp_file);
+
+  while (1) {
+    int res = 0;
+    /* blocking call */
+    res = socket_adapter.receive(&socket_adapter, pp_file);
+    if (res < 0) {
+      socket_adapter.close(&socket_adapter);
+      if (socket_adapter.reinit(&socket_adapter) != 0) {
+        socket_adapter.close(&socket_adapter);
+        usleep(MCELOG_POLL_TIMEOUT);
+      }
+      continue;
+    }
+    /* timeout or no data to read */
+    else if (res == 0)
+      continue;
+
+    if (*pp_file == NULL)
+      continue;
+
+    mcelog_memory_rec_t memory_record = {0};
+    while (parse_memory_info(*pp_file, &memory_record)) {
+      notification_t n = {NOTIF_OKAY, cdtime(), "", "",  MCELOG_PLUGIN,
+                          "",         "",       "", NULL};
+      ssnprintf(n.message, sizeof(n.message), "Got memory errors info.");
+      sstrncpy(n.type_instance, "memory_erros", sizeof(n.type_instance));
+      if (mcelog_prepare_notification(&n, memory_record) == 0)
+        mcelog_dispatch_notification(n);
+      if (mcelog_submit(memory_record) != 0)
+        ERROR("%s: Failed to submit memory errors", MCELOG_PLUGIN);
+      memset(&memory_record, 0, sizeof(memory_record));
+    }
+
+    fclose(*pp_file);
+    *pp_file = NULL;
+  }
+
+  mcelog_thread_running = 0;
+  pthread_cleanup_pop(1);
+  return NULL;
+}
+
+static int mcelog_init(void) {
+  if (socket_adapter.reinit(&socket_adapter) != 0) {
+    ERROR("%s: Cannot connect to client socket", MCELOG_PLUGIN);
+    return -1;
+  }
+
+  if (plugin_thread_create(&g_mcelog_config.tid, NULL, poll_worker, NULL,
+                           NULL) != 0) {
+    ERROR("%s: Error creating poll thread.", MCELOG_PLUGIN);
+    return -1;
+  }
+  return 0;
+}
+
+static int get_memory_machine_checks(void) {
+  static const char dump[] = "dump all bios\n";
+  int ret = socket_adapter.write(&socket_adapter, dump, sizeof(dump));
+  if (ret != 0)
+    ERROR("%s: SENT DUMP REQUEST FAILED", MCELOG_PLUGIN);
+  else
+    DEBUG("%s: SENT DUMP REQUEST OK", MCELOG_PLUGIN);
+  return ret;
+}
+
+static int mcelog_read(__attribute__((unused)) user_data_t *ud) {
+  DEBUG("%s: %s", MCELOG_PLUGIN, __FUNCTION__);
+
+  if (get_memory_machine_checks() != 0)
+    ERROR("%s: MACHINE CHECK INFO NOT AVAILABLE", MCELOG_PLUGIN);
+
+  return 0;
+}
+
+static int mcelog_shutdown(void) {
+  int ret = 0;
+  if (mcelog_thread_running) {
+    pthread_cancel(g_mcelog_config.tid);
+    if (pthread_join(g_mcelog_config.tid, NULL) != 0) {
+      ERROR("%s: Stopping thread failed.", MCELOG_PLUGIN);
+      ret = -1;
+    }
+  }
+
+  ret = socket_adapter.close(&socket_adapter) || ret;
+  pthread_rwlock_destroy(&(socket_adapter.lock));
+  return -ret;
+}
+
+void module_register(void) {
+  plugin_register_complex_config(MCELOG_PLUGIN, mcelog_config);
+  plugin_register_init(MCELOG_PLUGIN, mcelog_init);
+  plugin_register_complex_read(NULL, MCELOG_PLUGIN, mcelog_read, 0, NULL);
+  plugin_register_shutdown(MCELOG_PLUGIN, mcelog_shutdown);
+}
index 5b0827c..13e1db9 100644 (file)
@@ -674,7 +674,7 @@ static int submit_double(const char *host, const char *plugin_inst, /* {{{ */
                          const char *type, const char *type_inst, double d,
                          cdtime_t timestamp, cdtime_t interval) {
   return (submit_values(host, plugin_inst, type, type_inst,
-                        &(value_t){.gauge = counter}, 1, timestamp, interval));
+                        &(value_t){.gauge = d}, 1, timestamp, interval));
 } /* }}} int submit_uint64 */
 
 /* Calculate hit ratio from old and new counters and submit the resulting
@@ -1910,15 +1910,13 @@ static int cna_query_quota(host_config_t *host) /* {{{ */
 static int cna_handle_snapvault_data(const char *hostname, /* {{{ */
                                      cfg_snapvault_t *cfg_snapvault,
                                      na_elem_t *data, cdtime_t interval) {
-  na_elem_iter_t status_iter;
-
-  status = na_elem_child(data, "status-list");
-  if (!status) {
+  na_elem_t *status_list = na_elem_child(data, "status-list");
+  if (status_list == NULL) {
     ERROR("netapp plugin: SnapVault status record missing status-list");
     return (0);
   }
 
-  status_iter = na_child_iterator(status);
+  na_elem_iter_t status_iter = na_child_iterator(status_list);
   for (na_elem_t *status = na_iterator_next(&status_iter); status != NULL;
        status = na_iterator_next(&status_iter)) {
     const char *dest_sys, *dest_path, *src_sys, *src_path;
index 0649852..ddae5f2 100644 (file)
@@ -85,6 +85,11 @@ typedef struct ir_ignorelist_s {
   struct ir_ignorelist_s *next;
 } ir_ignorelist_t;
 
+struct qos_stats {
+  struct gnet_stats_basic *bs;
+  struct gnet_stats_queue *qs;
+};
+
 static int ir_ignorelist_invert = 1;
 static ir_ignorelist_t *ir_ignorelist_head = NULL;
 
@@ -387,20 +392,30 @@ static int link_filter_cb(const struct nlmsghdr *nlh,
 
 #if HAVE_TCA_STATS2
 static int qos_attr_cb(const struct nlattr *attr, void *data) {
-  struct gnet_stats_basic **bs = (struct gnet_stats_basic **)data;
+  struct qos_stats *q_stats = (struct qos_stats *)data;
 
   /* skip unsupported attribute in user-space */
   if (mnl_attr_type_valid(attr, TCA_STATS_MAX) < 0)
     return MNL_CB_OK;
 
   if (mnl_attr_get_type(attr) == TCA_STATS_BASIC) {
-    if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(**bs)) < 0) {
+    if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*q_stats->bs)) < 0) {
       ERROR("netlink plugin: qos_attr_cb: TCA_STATS_BASIC mnl_attr_validate2 "
             "failed.");
       return MNL_CB_ERROR;
     }
-    *bs = mnl_attr_get_payload(attr);
-    return MNL_CB_STOP;
+    q_stats->bs = mnl_attr_get_payload(attr);
+    return MNL_CB_OK;
+  }
+
+  if (mnl_attr_get_type(attr) == TCA_STATS_QUEUE) {
+    if (mnl_attr_validate2(attr, MNL_TYPE_UNSPEC, sizeof(*q_stats->qs)) < 0) {
+      ERROR("netlink plugin: qos_attr_cb: TCA_STATS_QUEUE mnl_attr_validate2 "
+            "failed.");
+      return MNL_CB_ERROR;
+    }
+    q_stats->qs = mnl_attr_get_payload(attr);
+    return MNL_CB_OK;
   }
 
   return MNL_CB_OK;
@@ -492,7 +507,9 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) {
 
 #if HAVE_TCA_STATS2
   mnl_attr_for_each(attr, nlh, sizeof(*tm)) {
-    struct gnet_stats_basic *bs = NULL;
+    struct qos_stats q_stats;
+
+    memset(&q_stats, 0x0, sizeof(q_stats));
 
     if (mnl_attr_get_type(attr) != TCA_STATS2)
       continue;
@@ -503,9 +520,9 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) {
       return MNL_CB_ERROR;
     }
 
-    mnl_attr_parse_nested(attr, qos_attr_cb, &bs);
+    mnl_attr_parse_nested(attr, qos_attr_cb, &q_stats);
 
-    if (bs != NULL) {
+    if (q_stats.bs != NULL || q_stats.qs != NULL) {
       char type_instance[DATA_MAX_NAME_LEN];
 
       stats_submitted = 1;
@@ -513,8 +530,13 @@ static int qos_filter_cb(const struct nlmsghdr *nlh, void *args) {
       ssnprintf(type_instance, sizeof(type_instance), "%s-%s", tc_type,
                 tc_inst);
 
-      submit_one(dev, "ipt_bytes", type_instance, bs->bytes);
-      submit_one(dev, "ipt_packets", type_instance, bs->packets);
+      if (q_stats.bs != NULL) {
+        submit_one(dev, "ipt_bytes", type_instance, q_stats.bs->bytes);
+        submit_one(dev, "ipt_packets", type_instance, q_stats.bs->packets);
+      }
+      if (q_stats.qs != NULL) {
+        submit_one(dev, "if_tx_dropped", type_instance, q_stats.qs->drops);
+      }
     }
 
     break;
diff --git a/src/ovs_events.c b/src/ovs_events.c
new file mode 100644 (file)
index 0000000..20af0c2
--- /dev/null
@@ -0,0 +1,639 @@
+/**
+ * collectd - src/ovs_events.c
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Volodymyr Mytnyk <volodymyrx.mytnyk@intel.com>
+ **/
+
+#include "collectd.h"
+
+#include "common.h" /* auxiliary functions */
+
+#include "utils_ovs.h" /* OVS helpers */
+
+#define OVS_EVENTS_IFACE_NAME_SIZE 128
+#define OVS_EVENTS_IFACE_UUID_SIZE 64
+#define OVS_EVENTS_EXT_IFACE_ID_SIZE 64
+#define OVS_EVENTS_EXT_VM_UUID_SIZE 64
+#define OVS_EVENTS_PLUGIN "ovs_events"
+#define OVS_EVENTS_CTX_LOCK                                                    \
+  for (int __i = ovs_events_ctx_lock(); __i != 0; __i = ovs_events_ctx_unlock())
+
+/* Link status type */
+enum ovs_events_link_status_e { DOWN, UP };
+typedef enum ovs_events_link_status_e ovs_events_link_status_t;
+
+/* Interface info */
+struct ovs_events_iface_info_s {
+  char name[OVS_EVENTS_IFACE_NAME_SIZE];           /* interface name */
+  char uuid[OVS_EVENTS_IFACE_UUID_SIZE];           /* interface UUID */
+  char ext_iface_id[OVS_EVENTS_EXT_IFACE_ID_SIZE]; /* external interface id */
+  char ext_vm_uuid[OVS_EVENTS_EXT_VM_UUID_SIZE];   /* external VM UUID */
+  ovs_events_link_status_t link_status;            /* interface link status */
+  struct ovs_events_iface_info_s *next;            /* next interface info */
+};
+typedef struct ovs_events_iface_info_s ovs_events_iface_info_t;
+
+/* Interface list */
+struct ovs_events_iface_list_s {
+  char name[OVS_EVENTS_IFACE_NAME_SIZE]; /* interface name */
+  struct ovs_events_iface_list_s *next;  /* next interface info */
+};
+typedef struct ovs_events_iface_list_s ovs_events_iface_list_t;
+
+/* OVS events configuration data */
+struct ovs_events_config_s {
+  _Bool send_notification;                 /* sent notification to collectd? */
+  char ovs_db_node[OVS_DB_ADDR_NODE_SIZE]; /* OVS DB node */
+  char ovs_db_serv[OVS_DB_ADDR_SERVICE_SIZE]; /* OVS DB service */
+  char ovs_db_unix[OVS_DB_ADDR_UNIX_SIZE];    /* OVS DB unix socket path */
+  ovs_events_iface_list_t *ifaces;            /* interface info */
+};
+typedef struct ovs_events_config_s ovs_events_config_t;
+
+/* OVS events context type */
+struct ovs_events_ctx_s {
+  pthread_mutex_t mutex;      /* mutex to lock the context */
+  ovs_db_t *ovs_db;           /* pointer to OVS DB instance */
+  ovs_events_config_t config; /* plugin config */
+  char *ovs_db_select_params; /* OVS DB select parameter request */
+  _Bool is_db_available;      /* specify whether OVS DB is available */
+};
+typedef struct ovs_events_ctx_s ovs_events_ctx_t;
+
+/*
+ * Private variables
+ */
+static ovs_events_ctx_t ovs_events_ctx = {
+    .mutex = PTHREAD_MUTEX_INITIALIZER,
+    .config = {.ovs_db_node = "localhost", /* use default OVS DB node */
+               .ovs_db_serv = "6640"}      /* use default OVS DB service */
+};
+
+/* This function is used only by "OVS_EVENTS_CTX_LOCK" define (see above).
+ * It always returns 1 when context is locked.
+ */
+static int ovs_events_ctx_lock() {
+  pthread_mutex_lock(&ovs_events_ctx.mutex);
+  return (1);
+}
+
+/* This function is used only by "OVS_EVENTS_CTX_LOCK" define (see above).
+ * It always returns 0 when context is unlocked.
+ */
+static int ovs_events_ctx_unlock() {
+  pthread_mutex_unlock(&ovs_events_ctx.mutex);
+  return (0);
+}
+
+/* Check if given interface name exists in configuration file. It
+ * returns 1 if exists otherwise 0. If no interfaces are configured,
+ * -1 is returned
+ */
+static int ovs_events_config_iface_exists(const char *ifname) {
+  if (ovs_events_ctx.config.ifaces == NULL)
+    return (-1);
+
+  /* check if given interface exists */
+  for (ovs_events_iface_list_t *iface = ovs_events_ctx.config.ifaces; iface;
+       iface = iface->next)
+    if (strcmp(ifname, iface->name) == 0)
+      return (1);
+
+  return (0);
+}
+
+/* Get OVS DB select parameter request based on rfc7047,
+ * "Transact" & "Select" section
+ */
+static char *ovs_events_get_select_params() {
+  size_t buff_size = 0;
+  size_t buff_off = 0;
+  char *opt_buff = NULL;
+  static const char params_fmt[] = "[\"Open_vSwitch\"%s]";
+  static const char option_fmt[] =
+      ",{\"op\":\"select\",\"table\":\"Interface\","
+      "\"where\":[[\"name\",\"==\",\"%s\"]],"
+      "\"columns\":[\"link_state\",\"external_ids\","
+      "\"name\",\"_uuid\"]}";
+  static const char default_opt[] =
+      ",{\"op\":\"select\",\"table\":\"Interface\","
+      "\"where\":[],\"columns\":[\"link_state\","
+      "\"external_ids\",\"name\",\"_uuid\"]}";
+  /* setup OVS DB interface condition */
+  for (ovs_events_iface_list_t *iface = ovs_events_ctx.config.ifaces; iface;
+       iface = iface->next) {
+    /* allocate new buffer (format size + ifname len is good enough) */
+    buff_size += sizeof(option_fmt) + strlen(iface->name);
+    char *new_buff = realloc(opt_buff, buff_size);
+    if (new_buff == NULL) {
+      sfree(opt_buff);
+      return NULL;
+    }
+    opt_buff = new_buff;
+    int ret = ssnprintf(opt_buff + buff_off, buff_size - buff_off, option_fmt,
+                        iface->name);
+    if (ret < 0) {
+      sfree(opt_buff);
+      return NULL;
+    }
+    buff_off += ret;
+  }
+  /* if no interfaces are configured, use default params */
+  if (opt_buff == NULL)
+    if ((opt_buff = strdup(default_opt)) == NULL)
+      return NULL;
+
+  /* allocate memory for OVS DB select params */
+  size_t params_size = sizeof(params_fmt) + strlen(opt_buff);
+  char *params_buff = calloc(1, params_size);
+  if (params_buff == NULL) {
+    sfree(opt_buff);
+    return NULL;
+  }
+
+  /* create OVS DB select params */
+  if (ssnprintf(params_buff, params_size, params_fmt, opt_buff) < 0)
+    sfree(params_buff);
+
+  sfree(opt_buff);
+  return params_buff;
+}
+
+/* Release memory allocated for configuration data */
+static void ovs_events_config_free() {
+  ovs_events_iface_list_t *del_iface = NULL;
+  sfree(ovs_events_ctx.ovs_db_select_params);
+  while (ovs_events_ctx.config.ifaces) {
+    del_iface = ovs_events_ctx.config.ifaces;
+    ovs_events_ctx.config.ifaces = ovs_events_ctx.config.ifaces->next;
+    sfree(del_iface);
+  }
+}
+
+/* Parse/process "Interfaces" configuration option. Returns 0 if success
+ * otherwise -1 (error)
+ */
+static int ovs_events_config_get_interfaces(const oconfig_item_t *ci) {
+  for (int j = 0; j < ci->values_num; j++) {
+    /* check interface name type */
+    if (ci->values[j].type != OCONFIG_TYPE_STRING) {
+      ERROR(OVS_EVENTS_PLUGIN
+            ": given interface name is not a string [idx=%d]", j);
+      return (-1);
+    }
+    /* allocate memory for configured interface */
+    ovs_events_iface_list_t *new_iface = calloc(1, sizeof(*new_iface));
+    if (new_iface == NULL) {
+      ERROR(OVS_EVENTS_PLUGIN ": calloc () copy interface name fail");
+      return (-1);
+    } else {
+      /* store interface name */
+      sstrncpy(new_iface->name, ci->values[j].value.string,
+               sizeof(new_iface->name));
+      new_iface->next = ovs_events_ctx.config.ifaces;
+      ovs_events_ctx.config.ifaces = new_iface;
+      DEBUG(OVS_EVENTS_PLUGIN ": found monitored interface \"%s\"",
+            new_iface->name);
+    }
+  }
+  return (0);
+}
+
+/* Parse plugin configuration file and store the config
+ * in allocated memory. Returns negative value in case of error.
+ */
+static int ovs_events_plugin_config(oconfig_item_t *ci) {
+  for (int i = 0; i < ci->children_num; i++) {
+    oconfig_item_t *child = ci->children + i;
+    if (strcasecmp("SendNotification", child->key) == 0) {
+      if (cf_util_get_boolean(child,
+                              &ovs_events_ctx.config.send_notification) != 0) {
+        ovs_events_config_free();
+        return (-1);
+      }
+    } else if (strcasecmp("Address", child->key) == 0) {
+      if (cf_util_get_string_buffer(
+              child, ovs_events_ctx.config.ovs_db_node,
+              sizeof(ovs_events_ctx.config.ovs_db_node)) != 0) {
+        ovs_events_config_free();
+        return (-1);
+      }
+    } else if (strcasecmp("Port", child->key) == 0) {
+      char *service = NULL;
+      if (cf_util_get_service(child, &service) != 0) {
+        ovs_events_config_free();
+        return (-1);
+      }
+      strncpy(ovs_events_ctx.config.ovs_db_serv, service,
+              sizeof(ovs_events_ctx.config.ovs_db_serv));
+      sfree(service);
+    } else if (strcasecmp("Socket", child->key) == 0) {
+      if (cf_util_get_string_buffer(
+              child, ovs_events_ctx.config.ovs_db_unix,
+              sizeof(ovs_events_ctx.config.ovs_db_unix)) != 0) {
+        ovs_events_config_free();
+        return (-1);
+      }
+    } else if (strcasecmp("Interfaces", child->key) == 0) {
+      if (ovs_events_config_get_interfaces(child) != 0) {
+        ovs_events_config_free();
+        return (-1);
+      }
+    } else {
+      ERROR(OVS_EVENTS_PLUGIN ": option '%s' is not allowed here", child->key);
+      ovs_events_config_free();
+      return (-1);
+    }
+  }
+  return (0);
+}
+
+/* Dispatch OVS interface link status event to collectd */
+static void ovs_events_dispatch_notification(const ovs_events_iface_info_t *ifinfo) {
+  const char *msg_link_status = NULL;
+  notification_t n = {
+      NOTIF_FAILURE, cdtime(), "", "", OVS_EVENTS_PLUGIN, "", "", "", NULL};
+
+  /* convert link status to message string */
+  switch (ifinfo->link_status) {
+  case UP:
+    msg_link_status = "UP";
+    n.severity = NOTIF_OKAY;
+    break;
+  case DOWN:
+    msg_link_status = "DOWN";
+    n.severity = NOTIF_WARNING;
+    break;
+  default:
+    ERROR(OVS_EVENTS_PLUGIN ": unknown interface link status");
+    return;
+  }
+
+  /* add interface metadata to the notification */
+  if (plugin_notification_meta_add_string(&n, "uuid", ifinfo->uuid) < 0) {
+    ERROR(OVS_EVENTS_PLUGIN ": add interface uuid meta data failed");
+    return;
+  }
+
+  if (strlen(ifinfo->ext_vm_uuid) > 0) {
+    if (plugin_notification_meta_add_string(&n, "vm-uuid",
+                                            ifinfo->ext_vm_uuid) < 0) {
+      ERROR(OVS_EVENTS_PLUGIN ": add interface vm-uuid meta data failed");
+      return;
+    }
+  }
+
+  if (strlen(ifinfo->ext_iface_id) > 0) {
+    if (plugin_notification_meta_add_string(&n, "iface-id",
+                                            ifinfo->ext_iface_id) < 0) {
+      ERROR(OVS_EVENTS_PLUGIN ": add interface iface-id meta data failed");
+      return;
+    }
+  }
+
+  /* fill the notification data */
+  ssnprintf(n.message, sizeof(n.message),
+            "link state of \"%s\" interface has been changed to \"%s\"",
+            ifinfo->name, msg_link_status);
+  sstrncpy(n.host, hostname_g, sizeof(n.host));
+  sstrncpy(n.plugin_instance, ifinfo->name, sizeof(n.plugin_instance));
+  sstrncpy(n.type, "gauge", sizeof(n.type));
+  sstrncpy(n.type_instance, "link_status", sizeof(n.type_instance));
+  plugin_dispatch_notification(&n);
+}
+
+/* Dispatch OVS interface link status value to collectd */
+static void ovs_events_link_status_submit(const ovs_events_iface_info_t *ifinfo) {
+  value_list_t vl = VALUE_LIST_INIT;
+  meta_data_t *meta = NULL;
+
+  /* add interface metadata to the submit value */
+  if ((meta = meta_data_create()) != NULL) {
+    if (meta_data_add_string(meta, "uuid", ifinfo->uuid) < 0)
+      ERROR(OVS_EVENTS_PLUGIN ": add interface uuid meta data failed");
+
+    if (strlen(ifinfo->ext_vm_uuid) > 0)
+      if (meta_data_add_string(meta, "vm-uuid", ifinfo->ext_vm_uuid) < 0)
+        ERROR(OVS_EVENTS_PLUGIN ": add interface vm-uuid meta data failed");
+
+    if (strlen(ifinfo->ext_iface_id) > 0)
+      if (meta_data_add_string(meta, "iface-id", ifinfo->ext_iface_id) < 0)
+        ERROR(OVS_EVENTS_PLUGIN ": add interface iface-id meta data failed");
+    vl.meta = meta;
+  } else
+    ERROR(OVS_EVENTS_PLUGIN ": create metadata failed");
+
+  vl.time = cdtime();
+  vl.values = &(value_t){.gauge = (gauge_t)ifinfo->link_status};
+  vl.values_len = 1;
+  sstrncpy(vl.plugin, OVS_EVENTS_PLUGIN, sizeof(vl.plugin));
+  sstrncpy(vl.plugin_instance, ifinfo->name, sizeof(vl.plugin_instance));
+  sstrncpy(vl.type, "gauge", sizeof(vl.type));
+  sstrncpy(vl.type_instance, "link_status", sizeof(vl.type_instance));
+  plugin_dispatch_values(&vl);
+  meta_data_destroy(meta);
+}
+
+/* Dispatch OVS DB terminate connection event to collectd */
+static void ovs_events_dispatch_terminate_notification(const char *msg) {
+  notification_t n = {
+      NOTIF_FAILURE, cdtime(), "", "", OVS_EVENTS_PLUGIN, "", "", "", NULL};
+  sstrncpy(n.message, msg, sizeof(n.message));
+  sstrncpy(n.host, hostname_g, sizeof(n.host));
+  plugin_dispatch_notification(&n);
+}
+
+/* Get OVS DB interface information and stores it into
+ * ovs_events_iface_info_t structure */
+static int ovs_events_get_iface_info(yajl_val jobject,
+                                     ovs_events_iface_info_t *ifinfo) {
+  yajl_val jexternal_ids = NULL;
+  yajl_val jvalue = NULL;
+  yajl_val juuid = NULL;
+  const char *state = NULL;
+
+  /* check YAJL type */
+  if (!YAJL_IS_OBJECT(jobject))
+    return (-1);
+
+  /* zero the interface info structure */
+  memset(ifinfo, 0, sizeof(*ifinfo));
+
+  /* try to find external_ids, name and link_state fields */
+  jexternal_ids = ovs_utils_get_value_by_key(jobject, "external_ids");
+  if (jexternal_ids == NULL || ifinfo == NULL)
+    return (-1);
+
+  /* get iface-id from external_ids field */
+  jvalue = ovs_utils_get_map_value(jexternal_ids, "iface-id");
+  if (jvalue != NULL && YAJL_IS_STRING(jvalue))
+    sstrncpy(ifinfo->ext_iface_id, YAJL_GET_STRING(jvalue),
+             sizeof(ifinfo->ext_iface_id));
+
+  /* get vm-uuid from external_ids field */
+  jvalue = ovs_utils_get_map_value(jexternal_ids, "vm-uuid");
+  if (jvalue != NULL && YAJL_IS_STRING(jvalue))
+    sstrncpy(ifinfo->ext_vm_uuid, YAJL_GET_STRING(jvalue),
+             sizeof(ifinfo->ext_vm_uuid));
+
+  /* get interface uuid */
+  jvalue = ovs_utils_get_value_by_key(jobject, "_uuid");
+  if (jvalue == NULL || !YAJL_IS_ARRAY(jvalue) ||
+      YAJL_GET_ARRAY(jvalue)->len != 2)
+    return (-1);
+  juuid = YAJL_GET_ARRAY(jvalue)->values[1];
+  if (juuid == NULL || !YAJL_IS_STRING(juuid))
+    return (-1);
+  sstrncpy(ifinfo->uuid, YAJL_GET_STRING(juuid), sizeof(ifinfo->uuid));
+
+  /* get interface name */
+  jvalue = ovs_utils_get_value_by_key(jobject, "name");
+  if (jvalue == NULL || !YAJL_IS_STRING(jvalue))
+    return (-1);
+  sstrncpy(ifinfo->name, YAJL_GET_STRING(jvalue), sizeof(ifinfo->name));
+
+  /* get OVS DB interface link status */
+  jvalue = ovs_utils_get_value_by_key(jobject, "link_state");
+  if (jvalue != NULL && ((state = YAJL_GET_STRING(jvalue)) != NULL)) {
+    /* convert OVS table link state to link status */
+    if (strcmp(state, "up") == 0)
+      ifinfo->link_status = UP;
+    else if (strcmp(state, "down") == 0)
+      ifinfo->link_status = DOWN;
+  }
+  return (0);
+}
+
+/* Process OVS DB update table event. It handles link status update event(s)
+ * and dispatches the value(s) to collectd if interface name matches one of
+ * interfaces specified in configuration file.
+ */
+static void ovs_events_table_update_cb(yajl_val jupdates) {
+  yajl_val jnew_val = NULL;
+  yajl_val jupdate = NULL;
+  yajl_val jrow_update = NULL;
+  ovs_events_iface_info_t ifinfo;
+
+  /* JSON "Interface" table update example:
+   * ---------------------------------
+   * {"Interface":
+   *  {
+   *   "9adf1db2-29ca-4140-ab22-ae347a4484de":
+   *    {
+   *     "new":
+   *      {
+   *       "name":"br0",
+   *       "link_state":"up"
+   *      },
+   *     "old":
+   *      {
+   *       "link_state":"down"
+   *      }
+   *    }
+   *  }
+   * }
+   */
+  if (!YAJL_IS_OBJECT(jupdates) || !(YAJL_GET_OBJECT(jupdates)->len > 0)) {
+    ERROR(OVS_EVENTS_PLUGIN ": unexpected OVS DB update event received");
+    return;
+  }
+  /* verify if this is a table event */
+  jupdate = YAJL_GET_OBJECT(jupdates)->values[0];
+  if (!YAJL_IS_OBJECT(jupdate)) {
+    ERROR(OVS_EVENTS_PLUGIN ": unexpected table update event received");
+    return;
+  }
+  /* go through all row updates  */
+  for (int row_index = 0; row_index < YAJL_GET_OBJECT(jupdate)->len;
+       ++row_index) {
+    jrow_update = YAJL_GET_OBJECT(jupdate)->values[row_index];
+
+    /* check row update */
+    jnew_val = ovs_utils_get_value_by_key(jrow_update, "new");
+    if (jnew_val == NULL) {
+      ERROR(OVS_EVENTS_PLUGIN ": unexpected row update received");
+      return;
+    }
+    /* get OVS DB interface information */
+    if (ovs_events_get_iface_info(jnew_val, &ifinfo) < 0) {
+      ERROR(OVS_EVENTS_PLUGIN
+            " :unexpected interface information data received");
+      return;
+    }
+    if (ovs_events_config_iface_exists(ifinfo.name) != 0) {
+      DEBUG("name=%s, uuid=%s, ext_iface_id=%s, ext_vm_uuid=%s", ifinfo.name,
+            ifinfo.uuid, ifinfo.ext_iface_id, ifinfo.ext_vm_uuid);
+      /* dispatch notification */
+      ovs_events_dispatch_notification(&ifinfo);
+    }
+  }
+}
+
+/* OVS DB reply callback. It parses reply, receives
+ * interface information and dispatches the info to
+ * collectd
+ */
+static void ovs_events_poll_result_cb(yajl_val jresult, yajl_val jerror) {
+  yajl_val *jvalues = NULL;
+  yajl_val jvalue = NULL;
+  ovs_events_iface_info_t ifinfo;
+
+  if (!YAJL_IS_NULL(jerror)) {
+    ERROR(OVS_EVENTS_PLUGIN "error received by OVS DB server");
+    return;
+  }
+
+  /* result should be an array */
+  if (!YAJL_IS_ARRAY(jresult)) {
+    ERROR(OVS_EVENTS_PLUGIN "invalid data (array is expected)");
+    return;
+  }
+
+  /* go through all rows and get interface info */
+  jvalues = YAJL_GET_ARRAY(jresult)->values;
+  for (int i = 0; i < YAJL_GET_ARRAY(jresult)->len; i++) {
+    jvalue = ovs_utils_get_value_by_key(jvalues[i], "rows");
+    if (jvalue == NULL || !YAJL_IS_ARRAY(jvalue)) {
+      ERROR(OVS_EVENTS_PLUGIN "invalid data (array of rows is expected)");
+      return;
+    }
+    /* get interfaces info */
+    for (int j = 0; j < YAJL_GET_ARRAY(jvalue)->len; j++) {
+      if (ovs_events_get_iface_info(YAJL_GET_ARRAY(jvalue)->values[j],
+                                    &ifinfo) < 0) {
+        ERROR(OVS_EVENTS_PLUGIN
+              "unexpected interface information data received");
+        return;
+      }
+      DEBUG("name=%s, uuid=%s, ext_iface_id=%s, ext_vm_uuid=%s", ifinfo.name,
+            ifinfo.uuid, ifinfo.ext_iface_id, ifinfo.ext_vm_uuid);
+      ovs_events_link_status_submit(&ifinfo);
+    }
+  }
+}
+
+/* Setup OVS DB table callback. It subscribes to OVS DB 'Interface' table
+ * to receive link status event(s).
+ */
+static void ovs_events_conn_initialize(ovs_db_t *pdb) {
+  const char tb_name[] = "Interface";
+  const char *columns[] = {"_uuid", "external_ids", "name", "link_state", NULL};
+
+  /* register update link status event if needed */
+  if (ovs_events_ctx.config.send_notification) {
+    int ret = ovs_db_table_cb_register(pdb, tb_name, columns,
+                                       ovs_events_table_update_cb, NULL,
+                                       OVS_DB_TABLE_CB_FLAG_MODIFY);
+    if (ret < 0) {
+      ERROR(OVS_EVENTS_PLUGIN ": register OVS DB update callback failed");
+      return;
+    }
+  }
+  OVS_EVENTS_CTX_LOCK { ovs_events_ctx.is_db_available = 1; }
+  DEBUG(OVS_EVENTS_PLUGIN ": OVS DB connection has been initialized");
+}
+
+/* OVS DB terminate connection notification callback */
+static void ovs_events_conn_terminate() {
+  const char msg[] = "OVS DB connection has been lost";
+  if (ovs_events_ctx.config.send_notification)
+    ovs_events_dispatch_terminate_notification(msg);
+  WARNING(OVS_EVENTS_PLUGIN ": %s", msg);
+  OVS_EVENTS_CTX_LOCK { ovs_events_ctx.is_db_available = 0; }
+}
+
+/* Read OVS DB interface link status callback */
+static int ovs_events_plugin_read(__attribute__((unused)) user_data_t *u) {
+  _Bool is_connected = 0;
+  OVS_EVENTS_CTX_LOCK { is_connected = ovs_events_ctx.is_db_available; }
+  if (is_connected)
+    if (ovs_db_send_request(ovs_events_ctx.ovs_db, "transact",
+                            ovs_events_ctx.ovs_db_select_params,
+                            ovs_events_poll_result_cb) < 0) {
+      ERROR(OVS_EVENTS_PLUGIN ": get interface info failed");
+      return (-1);
+    }
+  return (0);
+}
+
+/* Initialize OVS plugin */
+static int ovs_events_plugin_init(void) {
+  ovs_db_t *ovs_db = NULL;
+  ovs_db_callback_t cb = {.post_conn_init = ovs_events_conn_initialize,
+                          .post_conn_terminate = ovs_events_conn_terminate};
+
+  DEBUG(OVS_EVENTS_PLUGIN ": OVS DB address=%s, service=%s, unix=%s",
+        ovs_events_ctx.config.ovs_db_node, ovs_events_ctx.config.ovs_db_serv,
+        ovs_events_ctx.config.ovs_db_unix);
+
+  /* generate OVS DB select condition based on list on configured interfaces */
+  ovs_events_ctx.ovs_db_select_params = ovs_events_get_select_params();
+  if (ovs_events_ctx.ovs_db_select_params == NULL) {
+    ERROR(OVS_EVENTS_PLUGIN ": fail to get OVS DB select condition");
+    goto ovs_events_failure;
+  }
+
+  /* initialize OVS DB */
+  ovs_db = ovs_db_init(ovs_events_ctx.config.ovs_db_node,
+                       ovs_events_ctx.config.ovs_db_serv,
+                       ovs_events_ctx.config.ovs_db_unix, &cb);
+  if (ovs_db == NULL) {
+    ERROR(OVS_EVENTS_PLUGIN ": fail to connect to OVS DB server");
+    goto ovs_events_failure;
+  }
+
+  /* store OVS DB handler */
+  OVS_EVENTS_CTX_LOCK { ovs_events_ctx.ovs_db = ovs_db; }
+
+  DEBUG(OVS_EVENTS_PLUGIN ": plugin has been initialized");
+  return (0);
+
+ovs_events_failure:
+  ERROR(OVS_EVENTS_PLUGIN ": plugin initialize failed");
+  /* release allocated memory */
+  ovs_events_config_free();
+  return (-1);
+}
+
+/* Shutdown OVS plugin */
+static int ovs_events_plugin_shutdown(void) {
+  /* destroy OVS DB */
+  if (ovs_db_destroy(ovs_events_ctx.ovs_db))
+    ERROR(OVS_EVENTS_PLUGIN ": OVSDB object destroy failed");
+
+  /* release memory allocated for config */
+  ovs_events_config_free();
+
+  DEBUG(OVS_EVENTS_PLUGIN ": plugin has been destroyed");
+  return (0);
+}
+
+/* Register OVS plugin callbacks */
+void module_register(void) {
+  plugin_register_complex_config(OVS_EVENTS_PLUGIN, ovs_events_plugin_config);
+  plugin_register_init(OVS_EVENTS_PLUGIN, ovs_events_plugin_init);
+  plugin_register_complex_read(NULL, OVS_EVENTS_PLUGIN, ovs_events_plugin_read,
+                               0, NULL);
+  plugin_register_shutdown(OVS_EVENTS_PLUGIN, ovs_events_plugin_shutdown);
+}
index 8b2b556..e9dbc1d 100644 (file)
@@ -183,8 +183,11 @@ static void ts_subst(char *dest, size_t size, const char *string, /* {{{ */
   REPLACE_FIELD("%{type_instance}", vl->type_instance);
 
   if (vl->meta != NULL) {
-    char **meta_toc;
+    char **meta_toc = NULL;
     int meta_entries = meta_data_toc(vl->meta, &meta_toc);
+    if (meta_entries <= 0)
+      return;
+
     for (int i = 0; i < meta_entries; i++) {
       char meta_name[DATA_MAX_NAME_LEN];
       char *value_str;
@@ -358,6 +361,7 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */
         ERROR("Target `set': Unable to get replacement metadata value `%s'.",
               key);
         strarray_free(meta_toc, (size_t)meta_entries);
+        meta_data_destroy(new_meta);
         return (status);
       }
 
@@ -373,6 +377,7 @@ static int ts_invoke(const data_set_t *ds, value_list_t *vl, /* {{{ */
       if (status) {
         ERROR("Target `set': Unable to set metadata value `%s'.", key);
         strarray_free(meta_toc, (size_t)meta_entries);
+        meta_data_destroy(new_meta);
         return (status);
       }
     }
index 491d776..063548b 100644 (file)
@@ -155,46 +155,29 @@ int handle_getthreshold(FILE *fh, char *buffer) {
   print_to_socket(fh, "%zu Threshold found\n", i);
 
   if (threshold.host[0] != 0)
-    print_to_socket(fh, "Host: %s\n", threshold.host) if (
-        threshold.plugin[0] !=
-        0) print_to_socket(fh, "Plugin: %s\n",
-                           threshold.plugin) if (threshold.plugin_instance[0] !=
-                                                 0)
-        print_to_socket(fh, "Plugin Instance: %s\n",
-                        threshold.plugin_instance) if (threshold.type[0] != 0)
-            print_to_socket(fh, "Type: %s\n", threshold.type) if (
-                threshold.type_instance[0] !=
-                0) print_to_socket(fh, "Type Instance: %s\n",
-                                   threshold
-                                       .type_instance) if (threshold.data_source
-                                                               [0] != 0)
-                print_to_socket(
-                    fh, "Data Source: %s\n",
-                    threshold.data_source) if (!isnan(threshold.warning_min))
-                    print_to_socket(
-                        fh, "Warning Min: %g\n",
-                        threshold
-                            .warning_min) if (!isnan(threshold.warning_max))
-                        print_to_socket(
-                            fh, "Warning Max: %g\n",
-                            threshold
-                                .warning_max) if (!isnan(threshold.failure_min))
-                            print_to_socket(
-                                fh, "Failure Min: %g\n",
-                                threshold
-                                    .failure_min) if (!isnan(threshold
-                                                                 .failure_max))
-                                print_to_socket(
-                                    fh, "Failure Max: %g\n",
-                                    threshold.failure_max) if (threshold
-                                                                   .hysteresis >
-                                                               0.0)
-                                    print_to_socket(
-                                        fh, "Hysteresis: %g\n",
-                                        threshold.hysteresis) if (threshold
-                                                                      .hits > 1)
-                                        print_to_socket(fh, "Hits: %i\n",
-                                                        threshold.hits)
-
-                                            return (0);
+    print_to_socket(fh, "Host: %s\n", threshold.host);
+  if (threshold.plugin[0] != 0)
+    print_to_socket(fh, "Plugin: %s\n", threshold.plugin);
+  if (threshold.plugin_instance[0] != 0)
+    print_to_socket(fh, "Plugin Instance: %s\n", threshold.plugin_instance);
+  if (threshold.type[0] != 0)
+    print_to_socket(fh, "Type: %s\n", threshold.type);
+  if (threshold.type_instance[0] != 0)
+    print_to_socket(fh, "Type Instance: %s\n", threshold.type_instance);
+  if (threshold.data_source[0] != 0)
+    print_to_socket(fh, "Data Source: %s\n", threshold.data_source);
+  if (!isnan(threshold.warning_min))
+    print_to_socket(fh, "Warning Min: %g\n", threshold.warning_min);
+  if (!isnan(threshold.warning_max))
+    print_to_socket(fh, "Warning Max: %g\n", threshold.warning_max);
+  if (!isnan(threshold.failure_min))
+    print_to_socket(fh, "Failure Min: %g\n", threshold.failure_min);
+  if (!isnan(threshold.failure_max))
+    print_to_socket(fh, "Failure Max: %g\n", threshold.failure_max);
+  if (threshold.hysteresis > 0.0)
+    print_to_socket(fh, "Hysteresis: %g\n", threshold.hysteresis);
+  if (threshold.hits > 1)
+    print_to_socket(fh, "Hits: %i\n", threshold.hits);
+
+  return (0);
 } /* int handle_getthreshold */
diff --git a/src/utils_ovs.c b/src/utils_ovs.c
new file mode 100644 (file)
index 0000000..ff2b151
--- /dev/null
@@ -0,0 +1,1376 @@
+/**
+ * collectd - src/utils_ovs.c
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Volodymyr Mytnyk <volodymyrx.mytnyk@intel.com>
+ **/
+
+/* clang-format off */
+/*
+ *                         OVS DB API internal architecture diagram
+ * +------------------------------------------------------------------------------+
+ * |OVS plugin      |OVS utils                                                    |
+ * |                |     +------------------------+                              |
+ * |                |     |      echo handler      |                JSON request/ |
+ * |                |  +--+ (ovs_db_table_echo_cb) +<---+---------+ update event/ |
+ * |                |  |  |                        |    |         | result        |
+ * |                |  |  +------------------------+    |         |               |
+ * |                |  |                                |    +----+---+--------+  |
+ * |  +----------+  |  |  +------------------------+    |    |        |        |  |
+ * |  |  update  |  |  |  |     update handler     |    |    |  YAJL  |  JSON  |  |
+ * |  | callback +<-------+(ovs_db_table_update_cp)+<---+    | parser | reader |  |
+ * |  +----------+  |  |  |                        |    |    |        |        |  |
+ * |                |  |  +------------------------+    |    +--------+---+----+  |
+ * |                |  |                                |                 ^       |
+ * |  +----------+  |  |  +------------------------+    |                 |       |
+ * |  |  result  |  |  |  |     result handler     |    |                 |       |
+ * |  | callback +<-------+   (ovs_db_result_cb)   +<---+        JSON raw |       |
+ * |  +----------+  |  |  |                        |               data   |       |
+ * |                |  |  +------------------------+                      |       |
+ * |                |  |                                                  |       |
+ * |                |  |    +------------------+             +------------+----+  |
+ * |  +----------+  |  |    |thread|           |             |thread|          |  |
+ * |  |   init   |  |  |    |                  |  reconnect  |                 |  |
+ * |  | callback +<---------+   EVENT WORKER   +<------------+   POLL WORKER   |  |
+ * |  +----------+  |  |    +------------------+             +--------+--------+  |
+ * |                |  |                                              ^           |
+ * +----------------+-------------------------------------------------------------+
+ *                     |                                              |
+ *                 JSON|echo reply                                 raw|data
+ *                     v                                              v
+ * +-------------------+----------------------------------------------+-----------+
+ * |                                 TCP/UNIX socket                              |
+ * +-------------------------------------------------------------------------------
+ */
+/* clang-format on */
+
+/* collectd headers */
+#include "collectd.h"
+
+#include "common.h"
+
+/* private headers */
+#include "utils_ovs.h"
+
+/* system libraries */
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_POLL_H
+#include <poll.h>
+#endif
+#if HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
+#include <semaphore.h>
+
+#define OVS_ERROR(fmt, ...)                                                    \
+  do {                                                                         \
+    ERROR("ovs_utils: " fmt, ##__VA_ARGS__);                                   \
+  } while (0)
+#define OVS_DEBUG(fmt, ...)                                                    \
+  do {                                                                         \
+    DEBUG("%s:%d:%s(): " fmt, __FILE__, __LINE__, __FUNCTION__,                \
+          ##__VA_ARGS__);                                                      \
+  } while (0)
+
+#define OVS_DB_POLL_TIMEOUT 1           /* poll receive timeout (sec) */
+#define OVS_DB_POLL_READ_BLOCK_SIZE 512 /* read block size (bytes) */
+#define OVS_DB_DEFAULT_DB_NAME "Open_vSwitch"
+
+#define OVS_DB_EVENT_TIMEOUT 5 /* event thread timeout (sec) */
+#define OVS_DB_EVENT_TERMINATE 1
+#define OVS_DB_EVENT_CONN_ESTABLISHED 2
+#define OVS_DB_EVENT_CONN_TERMINATED 3
+
+#define OVS_DB_POLL_STATE_RUNNING 1
+#define OVS_DB_POLL_STATE_EXITING 2
+
+#define OVS_DB_SEND_REQ_TIMEOUT 5 /* send request timeout (sec) */
+
+#define OVS_YAJL_CALL(func, ...)                                               \
+  do {                                                                         \
+    yajl_gen_ret = yajl_gen_status_ok;                                         \
+    if ((yajl_gen_ret = func(__VA_ARGS__)) != yajl_gen_status_ok)              \
+      goto yajl_gen_failure;                                                   \
+  } while (0)
+#define OVS_YAJL_ERROR_BUFFER_SIZE 1024
+#define OVS_ERROR_BUFF_SIZE 512
+#define OVS_UID_STR_SIZE 17 /* 64-bit HEX string len + '\0' */
+
+/* JSON reader internal data */
+struct ovs_json_reader_s {
+  char *buff_ptr;
+  size_t buff_size;
+  size_t buff_offset;
+  size_t json_offset;
+};
+typedef struct ovs_json_reader_s ovs_json_reader_t;
+
+/* Result callback declaration */
+struct ovs_result_cb_s {
+  sem_t sync;
+  ovs_db_result_cb_t call;
+};
+typedef struct ovs_result_cb_s ovs_result_cb_t;
+
+/* Table callback declaration */
+struct ovs_table_cb_s {
+  ovs_db_table_cb_t call;
+};
+typedef struct ovs_table_cb_s ovs_table_cb_t;
+
+/* Callback declaration */
+struct ovs_callback_s {
+  uint64_t uid;
+  union {
+    ovs_result_cb_t result;
+    ovs_table_cb_t table;
+  };
+  struct ovs_callback_s *next;
+  struct ovs_callback_s *prev;
+};
+typedef struct ovs_callback_s ovs_callback_t;
+
+/* Event thread data declaration */
+struct ovs_event_thread_s {
+  pthread_t tid;
+  pthread_mutex_t mutex;
+  pthread_cond_t cond;
+  int value;
+};
+typedef struct ovs_event_thread_s ovs_event_thread_t;
+
+/* Poll thread data declaration */
+struct ovs_poll_thread_s {
+  pthread_t tid;
+  pthread_mutex_t mutex;
+  int state;
+};
+typedef struct ovs_poll_thread_s ovs_poll_thread_t;
+
+/* OVS DB internal data declaration */
+struct ovs_db_s {
+  ovs_poll_thread_t poll_thread;
+  ovs_event_thread_t event_thread;
+  pthread_mutex_t mutex;
+  ovs_callback_t *remote_cb;
+  ovs_db_callback_t cb;
+  char service[OVS_DB_ADDR_SERVICE_SIZE];
+  char node[OVS_DB_ADDR_NODE_SIZE];
+  char unix_path[OVS_DB_ADDR_NODE_SIZE];
+  int sock;
+};
+
+/* Global variables */
+static uint64_t ovs_uid = 0;
+static pthread_mutex_t ovs_uid_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* Post an event to event thread.
+ * Possible events are:
+ *  OVS_DB_EVENT_TERMINATE
+ *  OVS_DB_EVENT_CONN_ESTABLISHED
+ *  OVS_DB_EVENT_CONN_TERMINATED
+ */
+static void ovs_db_event_post(ovs_db_t *pdb, int event) {
+  pthread_mutex_lock(&pdb->event_thread.mutex);
+  pdb->event_thread.value = event;
+  pthread_mutex_unlock(&pdb->event_thread.mutex);
+  pthread_cond_signal(&pdb->event_thread.cond);
+}
+
+/* Check if POLL thread is still running. Returns
+ * 1 if running otherwise 0 is returned */
+static _Bool ovs_db_poll_is_running(ovs_db_t *pdb) {
+  int state = 0;
+  pthread_mutex_lock(&pdb->poll_thread.mutex);
+  state = pdb->poll_thread.state;
+  pthread_mutex_unlock(&pdb->poll_thread.mutex);
+  return (state == OVS_DB_POLL_STATE_RUNNING);
+}
+
+/* Generate unique identifier (UID). It is used by OVS DB API
+ * to set "id" field for any OVS DB JSON request. */
+static uint64_t ovs_uid_generate() {
+  uint64_t new_uid;
+  pthread_mutex_lock(&ovs_uid_mutex);
+  new_uid = ++ovs_uid;
+  pthread_mutex_unlock(&ovs_uid_mutex);
+  return new_uid;
+}
+
+/*
+ * Callback API. These function are used to store
+ * registered callbacks in OVS DB API.
+ */
+
+/* Add new callback into OVS DB object */
+static void ovs_db_callback_add(ovs_db_t *pdb, ovs_callback_t *new_cb) {
+  pthread_mutex_lock(&pdb->mutex);
+  if (pdb->remote_cb)
+    pdb->remote_cb->prev = new_cb;
+  new_cb->next = pdb->remote_cb;
+  new_cb->prev = NULL;
+  pdb->remote_cb = new_cb;
+  pthread_mutex_unlock(&pdb->mutex);
+}
+
+/* Remove callback from OVS DB object */
+static void ovs_db_callback_remove(ovs_db_t *pdb, ovs_callback_t *del_cb) {
+  pthread_mutex_lock(&pdb->mutex);
+  ovs_callback_t *pre_cb = del_cb->prev;
+  ovs_callback_t *next_cb = del_cb->next;
+
+  if (next_cb)
+    next_cb->prev = del_cb->prev;
+
+  if (pre_cb)
+    pre_cb->next = del_cb->next;
+  else
+    pdb->remote_cb = del_cb->next;
+
+  free(del_cb);
+  pthread_mutex_unlock(&pdb->mutex);
+}
+
+/* Remove all callbacks form OVS DB object */
+static void ovs_db_callback_remove_all(ovs_db_t *pdb) {
+  pthread_mutex_lock(&pdb->mutex);
+  for (ovs_callback_t *del_cb = pdb->remote_cb; pdb->remote_cb;
+       del_cb = pdb->remote_cb) {
+    pdb->remote_cb = del_cb->next;
+    free(del_cb);
+  }
+  pdb->remote_cb = NULL;
+  pthread_mutex_unlock(&pdb->mutex);
+}
+
+/* Get/find callback in OVS DB object by UID. Returns pointer
+ * to requested callback otherwise NULL is returned.
+ *
+ * IMPORTANT NOTE:
+ *   The OVS DB mutex MUST be locked by the caller
+ *   to make sure that returned callback is still valid.
+ */
+static ovs_callback_t *ovs_db_callback_get(ovs_db_t *pdb, uint64_t uid) {
+  for (ovs_callback_t *cb = pdb->remote_cb; cb != NULL; cb = cb->next)
+    if (cb->uid == uid)
+      return cb;
+  return NULL;
+}
+
+/* Send all requested data to the socket. Returns 0 if
+ * ALL request data has been sent otherwise negative value
+ * is returned */
+static int ovs_db_data_send(const ovs_db_t *pdb, const char *data, size_t len) {
+  ssize_t nbytes = 0;
+  size_t rem = len;
+  size_t off = 0;
+
+  while (rem > 0) {
+    if ((nbytes = send(pdb->sock, data + off, rem, 0)) <= 0)
+      return (-1);
+    rem -= (size_t)nbytes;
+    off += (size_t)nbytes;
+  }
+  return (0);
+}
+
+/*
+ * YAJL (Yet Another JSON Library) helper functions
+ * Documentation (https://lloyd.github.io/yajl/)
+ */
+
+/* Add null-terminated string into YAJL generator handle (JSON object).
+ * Similar function to yajl_gen_string() but takes null-terminated string
+ * instead of string and its length.
+ *
+ * jgen   - YAJL generator handle allocated by yajl_gen_alloc()
+ * string - Null-terminated string
+ */
+static yajl_gen_status ovs_yajl_gen_tstring(yajl_gen hander,
+                                            const char *string) {
+  return yajl_gen_string(hander, (const unsigned char *)string, strlen(string));
+}
+
+/* Add YAJL value into YAJL generator handle (JSON object)
+ *
+ * jgen - YAJL generator handle allocated by yajl_gen_alloc()
+ * jval - YAJL value usually returned by yajl_tree_get()
+ */
+static yajl_gen_status ovs_yajl_gen_val(yajl_gen jgen, yajl_val jval) {
+  size_t array_len = 0;
+  yajl_val *jvalues = NULL;
+  yajl_val jobj_value = NULL;
+  const char *obj_key = NULL;
+  size_t obj_len = 0;
+  yajl_gen_status yajl_gen_ret;
+
+  if (YAJL_IS_STRING(jval))
+    OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, YAJL_GET_STRING(jval));
+  else if (YAJL_IS_DOUBLE(jval))
+    OVS_YAJL_CALL(yajl_gen_double, jgen, YAJL_GET_DOUBLE(jval));
+  else if (YAJL_IS_INTEGER(jval))
+    OVS_YAJL_CALL(yajl_gen_double, jgen, YAJL_GET_INTEGER(jval));
+  else if (YAJL_IS_TRUE(jval))
+    OVS_YAJL_CALL(yajl_gen_bool, jgen, 1);
+  else if (YAJL_IS_FALSE(jval))
+    OVS_YAJL_CALL(yajl_gen_bool, jgen, 0);
+  else if (YAJL_IS_NULL(jval))
+    OVS_YAJL_CALL(yajl_gen_null, jgen);
+  else if (YAJL_IS_ARRAY(jval)) {
+    /* create new array and add all elements into the array */
+    array_len = YAJL_GET_ARRAY(jval)->len;
+    jvalues = YAJL_GET_ARRAY(jval)->values;
+    OVS_YAJL_CALL(yajl_gen_array_open, jgen);
+    for (int i = 0; i < array_len; i++)
+      OVS_YAJL_CALL(ovs_yajl_gen_val, jgen, jvalues[i]);
+    OVS_YAJL_CALL(yajl_gen_array_close, jgen);
+  } else if (YAJL_IS_OBJECT(jval)) {
+    /* create new object and add all elements into the object */
+    OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+    obj_len = YAJL_GET_OBJECT(jval)->len;
+    for (int i = 0; i < obj_len; i++) {
+      obj_key = YAJL_GET_OBJECT(jval)->keys[i];
+      jobj_value = YAJL_GET_OBJECT(jval)->values[i];
+      OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, obj_key);
+      OVS_YAJL_CALL(ovs_yajl_gen_val, jgen, jobj_value);
+    }
+    OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+  } else {
+    OVS_ERROR("%s() unsupported value type %d (skip)", __FUNCTION__,
+              (int)(jval)->type);
+    goto yajl_gen_failure;
+  }
+  return yajl_gen_status_ok;
+
+yajl_gen_failure:
+  OVS_ERROR("%s() error to generate value", __FUNCTION__);
+  return yajl_gen_ret;
+}
+
+/* OVS DB echo request handler. When OVS DB sends
+ * "echo" request to the client, client should generate
+ * "echo" replay with the same content received in the
+ * request */
+static int ovs_db_table_echo_cb(const ovs_db_t *pdb, yajl_val jnode) {
+  yajl_val jparams;
+  yajl_val jid;
+  yajl_gen jgen;
+  size_t resp_len = 0;
+  const char *resp = NULL;
+  const char *params_path[] = {"params", NULL};
+  const char *id_path[] = {"id", NULL};
+  yajl_gen_status yajl_gen_ret;
+
+  if ((jgen = yajl_gen_alloc(NULL)) == NULL)
+    return (-1);
+
+  /* check & get request attributes */
+  if ((jparams = yajl_tree_get(jnode, params_path, yajl_t_array)) == NULL ||
+      ((jid = yajl_tree_get(jnode, id_path, yajl_t_any)) == NULL)) {
+    OVS_ERROR("parse echo request failed");
+    goto yajl_gen_failure;
+  }
+
+  /* generate JSON echo response */
+  OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "result");
+  OVS_YAJL_CALL(ovs_yajl_gen_val, jgen, jparams);
+
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "error");
+  OVS_YAJL_CALL(yajl_gen_null, jgen);
+
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "id");
+  OVS_YAJL_CALL(ovs_yajl_gen_val, jgen, jid);
+
+  OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+  OVS_YAJL_CALL(yajl_gen_get_buf, jgen, (const unsigned char **)&resp,
+                &resp_len);
+
+  /* send the response */
+  OVS_DEBUG("response: %s", resp);
+  if (ovs_db_data_send(pdb, resp, resp_len) < 0) {
+    OVS_ERROR("send echo reply failed");
+    goto yajl_gen_failure;
+  }
+  /* clean up and return success */
+  yajl_gen_clear(jgen);
+  return (0);
+
+yajl_gen_failure:
+  /* release memory */
+  yajl_gen_clear(jgen);
+  return (-1);
+}
+
+/* Get OVS DB registered callback by YAJL val. The YAJL
+ * value should be YAJL string (UID). Returns NULL if
+ * callback hasn't been found. See also ovs_db_callback_get()
+ * description for addition info.
+ */
+static ovs_callback_t *ovs_db_table_callback_get(ovs_db_t *pdb, yajl_val jid) {
+  char *endptr = NULL;
+  const char *suid = NULL;
+  uint64_t uid;
+
+  if (jid && YAJL_IS_STRING(jid)) {
+    suid = YAJL_GET_STRING(jid);
+    uid = (uint64_t)strtoul(suid, &endptr, 16);
+    if (*endptr == '\0' && uid)
+      return ovs_db_callback_get(pdb, uid);
+  }
+
+  return NULL;
+}
+
+/* OVS DB table update event handler.
+ * This callback is called by POLL thread if OVS DB
+ * table update callback is received from the DB
+ * server. Once registered callback found, it's called
+ * by this handler. */
+static int ovs_db_table_update_cb(ovs_db_t *pdb, yajl_val jnode) {
+  ovs_callback_t *cb = NULL;
+  yajl_val jvalue;
+  yajl_val jparams;
+  yajl_val jtable_updates;
+  yajl_val jtable_update;
+  size_t obj_len = 0;
+  const char *table_name = NULL;
+  const char *params_path[] = {"params", NULL};
+  const char *id_path[] = {"id", NULL};
+
+  /* check & get request attributes */
+  if ((jparams = yajl_tree_get(jnode, params_path, yajl_t_array)) == NULL ||
+      (yajl_tree_get(jnode, id_path, yajl_t_null) == NULL)) {
+    OVS_ERROR("invalid OVS DB request received");
+    return (-1);
+  }
+
+  /* check array length: [<json-value>, <table-updates>] */
+  if ((YAJL_GET_ARRAY(jparams) == NULL) ||
+      (YAJL_GET_ARRAY(jparams)->len != 2)) {
+    OVS_ERROR("invalid OVS DB request received");
+    return (-1);
+  }
+
+  jvalue = YAJL_GET_ARRAY(jparams)->values[0];
+  jtable_updates = YAJL_GET_ARRAY(jparams)->values[1];
+  if ((!YAJL_IS_OBJECT(jtable_updates)) || (!YAJL_IS_STRING(jvalue))) {
+    OVS_ERROR("invalid OVS DB request id or table update received");
+    return (-1);
+  }
+
+  /* find registered callback based on <json-value> */
+  pthread_mutex_lock(&pdb->mutex);
+  cb = ovs_db_table_callback_get(pdb, jvalue);
+  if (cb == NULL || cb->table.call == NULL) {
+    OVS_ERROR("No OVS DB table update callback found");
+    pthread_mutex_unlock(&pdb->mutex);
+    return (-1);
+  }
+
+  /* call registered callback */
+  cb->table.call(jtable_updates);
+  pthread_mutex_unlock(&pdb->mutex);
+  return 0;
+}
+
+/* OVS DB result request handler.
+ * This callback is called by POLL thread if OVS DB
+ * result reply is received from the DB server.
+ * Once registered callback found, it's called
+ * by this handler. */
+static int ovs_db_result_cb(ovs_db_t *pdb, yajl_val jnode) {
+  ovs_callback_t *cb = NULL;
+  yajl_val jresult;
+  yajl_val jerror;
+  yajl_val jid;
+  const char *result_path[] = {"result", NULL};
+  const char *error_path[] = {"error", NULL};
+  const char *id_path[] = {"id", NULL};
+
+  jresult = yajl_tree_get(jnode, result_path, yajl_t_any);
+  jerror = yajl_tree_get(jnode, error_path, yajl_t_any);
+  jid = yajl_tree_get(jnode, id_path, yajl_t_string);
+
+  /* check & get result attributes */
+  if (!jresult || !jerror || !jid)
+    return (-1);
+
+  /* try to find registered callback */
+  pthread_mutex_lock(&pdb->mutex);
+  cb = ovs_db_table_callback_get(pdb, jid);
+  if (cb != NULL && cb->result.call != NULL) {
+    /* call registered callback */
+    cb->result.call(jresult, jerror);
+    /* unlock owner of the reply */
+    sem_post(&cb->result.sync);
+  }
+
+  pthread_mutex_unlock(&pdb->mutex);
+  return (0);
+}
+
+/* Handle JSON data (one request) and call
+ * appropriate event OVS DB handler. Currently,
+ * update callback 'ovs_db_table_update_cb' and
+ * result callback 'ovs_db_result_cb' is supported.
+ */
+static int ovs_db_json_data_process(ovs_db_t *pdb, const char *data,
+                                    size_t len) {
+  const char *method = NULL;
+  char yajl_errbuf[OVS_YAJL_ERROR_BUFFER_SIZE];
+  const char *method_path[] = {"method", NULL};
+  const char *result_path[] = {"result", NULL};
+  char *sjson = NULL;
+  yajl_val jnode, jval;
+
+  /* duplicate the data to make null-terminated string
+   * required for yajl_tree_parse() */
+  if ((sjson = calloc(1, len + 1)) == NULL)
+    return (-1);
+
+  sstrncpy(sjson, data, len + 1);
+  OVS_DEBUG("[len=%zu] %s", len, sjson);
+
+  /* parse json data */
+  jnode = yajl_tree_parse(sjson, yajl_errbuf, sizeof(yajl_errbuf));
+  if (jnode == NULL) {
+    OVS_ERROR("yajl_tree_parse() %s", yajl_errbuf);
+    sfree(sjson);
+    return (-1);
+  }
+
+  /* get method name */
+  if ((jval = yajl_tree_get(jnode, method_path, yajl_t_string)) != NULL) {
+    method = YAJL_GET_STRING(jval);
+    if (strcmp("echo", method) == 0) {
+      /* echo request from the server */
+      if (ovs_db_table_echo_cb(pdb, jnode) < 0)
+        OVS_ERROR("handle echo request failed");
+    } else if (strcmp("update", method) == 0) {
+      /* update notification */
+      if (ovs_db_table_update_cb(pdb, jnode) < 0)
+        OVS_ERROR("handle update notification failed");
+    }
+  } else if ((jval = yajl_tree_get(jnode, result_path, yajl_t_any)) != NULL) {
+    /* result notification */
+    if (ovs_db_result_cb(pdb, jnode) < 0)
+      OVS_ERROR("handle result reply failed");
+  } else
+    OVS_ERROR("connot find method or result failed");
+
+  /* release memory */
+  yajl_tree_free(jnode);
+  sfree(sjson);
+  return (0);
+}
+
+/*
+ * JSON reader implementation.
+ *
+ * This module process raw JSON data (byte stream) and
+ * returns fully-fledged JSON data which can be processed
+ * (parsed) by YAJL later.
+ */
+
+/* Allocate JSON reader instance */
+static ovs_json_reader_t *ovs_json_reader_alloc() {
+  ovs_json_reader_t *jreader = NULL;
+
+  if ((jreader = calloc(sizeof(ovs_json_reader_t), 1)) == NULL)
+    return NULL;
+
+  return jreader;
+}
+
+/* Push raw data into into the JSON reader for processing */
+static int ovs_json_reader_push_data(ovs_json_reader_t *jreader,
+                                     const char *data, size_t data_len) {
+  char *new_buff = NULL;
+  size_t available = jreader->buff_size - jreader->buff_offset;
+
+  /* check/update required memory space */
+  if (available < data_len) {
+    OVS_DEBUG("Reallocate buffer [size=%d, available=%d required=%d]",
+              (int)jreader->buff_size, (int)available, (int)data_len);
+
+    /* allocate new chunk of memory */
+    new_buff = realloc(jreader->buff_ptr, (jreader->buff_size + data_len));
+    if (new_buff == NULL)
+      return (-1);
+
+    /* point to new allocated memory */
+    jreader->buff_ptr = new_buff;
+    jreader->buff_size += data_len;
+  }
+
+  /* store input data */
+  memcpy(jreader->buff_ptr + jreader->buff_offset, data, data_len);
+  jreader->buff_offset += data_len;
+  return (0);
+}
+
+/* Pop one fully-fledged JSON if already exists. Returns 0 if
+ * completed JSON already exists otherwise negative value is
+ * returned */
+static int ovs_json_reader_pop(ovs_json_reader_t *jreader,
+                               const char **json_ptr, size_t *json_len_ptr) {
+  size_t nbraces = 0;
+  size_t json_len = 0;
+  char *json = NULL;
+
+  /* search open/close brace */
+  for (int i = jreader->json_offset; i < jreader->buff_offset; i++) {
+    if (jreader->buff_ptr[i] == '{') {
+      nbraces++;
+    } else if (jreader->buff_ptr[i] == '}')
+      if (nbraces)
+        if (!(--nbraces)) {
+          /* JSON data */
+          *json_ptr = jreader->buff_ptr + jreader->json_offset;
+          *json_len_ptr = json_len + 1;
+          jreader->json_offset = i + 1;
+          return (0);
+        }
+
+    /* increase JSON data length */
+    if (nbraces)
+      json_len++;
+  }
+
+  if (jreader->json_offset) {
+    if (jreader->json_offset < jreader->buff_offset) {
+      /* shift data to the beginning of the buffer
+       * and zero rest of the buffer data */
+      json = &jreader->buff_ptr[jreader->json_offset];
+      json_len = jreader->buff_offset - jreader->json_offset;
+      for (int i = 0; i < jreader->buff_size; i++)
+        jreader->buff_ptr[i] = ((i < json_len) ? (json[i]) : (0));
+      jreader->buff_offset = json_len;
+    } else
+      /* reset the buffer */
+      jreader->buff_offset = 0;
+
+    /* data is at the beginning of the buffer */
+    jreader->json_offset = 0;
+  }
+
+  return (-1);
+}
+
+/* Reset JSON reader. It is useful when start processing
+ * new raw data. E.g.: in case of lost stream connection.
+ */
+static void ovs_json_reader_reset(ovs_json_reader_t *jreader) {
+  if (jreader) {
+    jreader->buff_offset = 0;
+    jreader->json_offset = 0;
+  }
+}
+
+/* Release internal data allocated for JSON reader */
+static void ovs_json_reader_free(ovs_json_reader_t *jreader) {
+  if (jreader) {
+    free(jreader->buff_ptr);
+    free(jreader);
+  }
+}
+
+/* Reconnect to OVS DB and call the OVS DB post connection init callback
+ * if connection has been established.
+ */
+static void ovs_db_reconnect(ovs_db_t *pdb) {
+  const char unix_prefix[] = "unix:";
+  const char *node_info = pdb->node;
+  struct addrinfo *result;
+  struct sockaddr_un saunix;
+
+  if (pdb->unix_path[0] != '\0') {
+    /* use UNIX socket instead of INET address */
+    node_info = pdb->unix_path;
+    result = calloc(1, sizeof(struct addrinfo));
+    struct sockaddr_un *sa_unix = calloc(1, sizeof(struct sockaddr_un));
+    if (result == NULL || sa_unix == NULL) {
+      sfree(result);
+      sfree(sa_unix);
+      return;
+    }
+    result->ai_family = AF_UNIX;
+    result->ai_socktype = SOCK_STREAM;
+    result->ai_addrlen = sizeof(*sa_unix);
+    result->ai_addr = (struct sockaddr *)sa_unix;
+    sa_unix->sun_family = result->ai_family;
+    sstrncpy(sa_unix->sun_path, pdb->unix_path, sizeof(sa_unix->sun_path));
+  } else {
+    /* inet socket address */
+    struct addrinfo hints;
+
+    /* setup criteria for selecting the socket address */
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_family = AF_UNSPEC;
+    hints.ai_socktype = SOCK_STREAM;
+
+    /* get socket addresses */
+    int ret = getaddrinfo(pdb->node, pdb->service, &hints, &result);
+    if (ret != 0) {
+      OVS_ERROR("getaddrinfo(): %s", gai_strerror(ret));
+      return;
+    }
+  }
+  /* try to connect to the server */
+  for (struct addrinfo *rp = result; rp != NULL; rp = rp->ai_next) {
+    char errbuff[OVS_ERROR_BUFF_SIZE];
+    int sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
+    if (sock < 0) {
+      sstrerror(errno, errbuff, sizeof(errbuff));
+      OVS_DEBUG("socket(): %s", errbuff);
+      continue;
+    }
+    if (connect(sock, rp->ai_addr, rp->ai_addrlen) < 0) {
+      close(sock);
+      sstrerror(errno, errbuff, sizeof(errbuff));
+      OVS_DEBUG("connect(): %s [family=%d]", errbuff, rp->ai_family);
+    } else {
+      /* send notification to event thread */
+      ovs_db_event_post(pdb, OVS_DB_EVENT_CONN_ESTABLISHED);
+      pdb->sock = sock;
+      break;
+    }
+  }
+
+  if (pdb->sock < 0)
+    OVS_ERROR("connect to \"%s\" failed", node_info);
+
+  freeaddrinfo(result);
+}
+
+/* POLL worker thread.
+ * It listens on OVS DB connection for incoming
+ * requests/reply/events etc. Also, it reconnects to OVS DB
+ * if connection has been lost.
+ */
+static void *ovs_poll_worker(void *arg) {
+  ovs_db_t *pdb = (ovs_db_t *)arg; /* pointer to OVS DB */
+  ovs_json_reader_t *jreader = NULL;
+  struct pollfd poll_fd = {
+      .fd = pdb->sock, .events = POLLIN | POLLPRI, .revents = 0,
+  };
+
+  /* create JSON reader instance */
+  if ((jreader = ovs_json_reader_alloc()) == NULL) {
+    OVS_ERROR("initialize json reader failed");
+    return (NULL);
+  }
+
+  /* poll data */
+  while (ovs_db_poll_is_running(pdb)) {
+    char errbuff[OVS_ERROR_BUFF_SIZE];
+    poll_fd.fd = pdb->sock;
+    int poll_ret = poll(&poll_fd, 1, /* ms */ OVS_DB_POLL_TIMEOUT * 1000);
+    if (poll_ret < 0) {
+      sstrerror(errno, errbuff, sizeof(errbuff));
+      OVS_ERROR("poll(): %s", errbuff);
+      break;
+    } else if (poll_ret == 0) {
+      OVS_DEBUG("poll(): timeout");
+      if (pdb->sock < 0)
+        /* invalid fd, so try to reconnect */
+        ovs_db_reconnect(pdb);
+      continue;
+    }
+    if (poll_fd.revents & POLLNVAL) {
+      /* invalid file descriptor, clean-up */
+      ovs_db_callback_remove_all(pdb);
+      ovs_json_reader_reset(jreader);
+      /* setting poll FD to -1 tells poll() call to ignore this FD.
+       * In that case poll() call will return timeout all the time */
+      pdb->sock = (-1);
+    } else if ((poll_fd.revents & POLLERR) || (poll_fd.revents & POLLHUP)) {
+      /* connection is broken */
+      close(poll_fd.fd);
+      ovs_db_event_post(pdb, OVS_DB_EVENT_CONN_TERMINATED);
+      OVS_ERROR("poll() peer closed its end of the channel");
+    } else if ((poll_fd.revents & POLLIN) || (poll_fd.revents & POLLPRI)) {
+      /* read incoming data */
+      char buff[OVS_DB_POLL_READ_BLOCK_SIZE];
+      ssize_t nbytes = recv(poll_fd.fd, buff, sizeof(buff), 0);
+      if (nbytes < 0) {
+        sstrerror(errno, errbuff, sizeof(errbuff));
+        OVS_ERROR("recv(): %s", errbuff);
+        /* read error? Try to reconnect */
+        close(poll_fd.fd);
+        continue;
+      } else if (nbytes == 0) {
+        close(poll_fd.fd);
+        ovs_db_event_post(pdb, OVS_DB_EVENT_CONN_TERMINATED);
+        OVS_ERROR("recv() peer has performed an orderly shutdown");
+        continue;
+      }
+      /* read incoming data */
+      size_t json_len = 0;
+      const char *json = NULL;
+      OVS_DEBUG("recv(): received %zd bytes of data", nbytes);
+      ovs_json_reader_push_data(jreader, buff, nbytes);
+      while (!ovs_json_reader_pop(jreader, &json, &json_len))
+        /* process JSON data */
+        ovs_db_json_data_process(pdb, json, json_len);
+    }
+  }
+
+  OVS_DEBUG("poll thread has been completed");
+  ovs_json_reader_free(jreader);
+  return (NULL);
+}
+
+/* EVENT worker thread.
+ * Perform task based on incoming events. This
+ * task can be done asynchronously which allows to
+ * handle OVS DB callback like 'init_cb'.
+ */
+static void *ovs_event_worker(void *arg) {
+  ovs_db_t *pdb = (ovs_db_t *)arg;
+
+  while (pdb->event_thread.value != OVS_DB_EVENT_TERMINATE) {
+    /* wait for an event */
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    ts.tv_sec += (OVS_DB_EVENT_TIMEOUT);
+    int ret = pthread_cond_timedwait(&pdb->event_thread.cond,
+                                     &pdb->event_thread.mutex, &ts);
+    if (!ret) {
+      /* handle the event */
+      OVS_DEBUG("handle event %d", pdb->event_thread.value);
+      switch (pdb->event_thread.value) {
+      case OVS_DB_EVENT_CONN_ESTABLISHED:
+        if (pdb->cb.post_conn_init)
+          pdb->cb.post_conn_init(pdb);
+        break;
+      case OVS_DB_EVENT_CONN_TERMINATED:
+        if (pdb->cb.post_conn_terminate)
+          pdb->cb.post_conn_terminate();
+        break;
+      default:
+        OVS_DEBUG("unknown event received");
+        break;
+      }
+    } else if (ret == ETIMEDOUT) {
+      /* wait timeout */
+      OVS_DEBUG("no event received (timeout)");
+      continue;
+    } else {
+      /* unexpected error */
+      OVS_ERROR("pthread_cond_timedwait() failed");
+      break;
+    }
+  }
+
+  OVS_DEBUG("event thread has been completed");
+  return (NULL);
+}
+
+/* Initialize EVENT thread */
+static int ovs_db_event_thread_init(ovs_db_t *pdb) {
+  pdb->event_thread.tid = -1;
+  /* init event thread condition variable */
+  if (pthread_cond_init(&pdb->event_thread.cond, NULL)) {
+    return (-1);
+  }
+  /* init event thread mutex */
+  if (pthread_mutex_init(&pdb->event_thread.mutex, NULL)) {
+    pthread_cond_destroy(&pdb->event_thread.cond);
+    return (-1);
+  }
+  /* Hold the event thread mutex. It ensures that no events
+   * will be lost while thread is still starting. Once event
+   * thread is started and ready to accept events, it will release
+   * the mutex */
+  if (pthread_mutex_lock(&pdb->event_thread.mutex)) {
+    pthread_mutex_destroy(&pdb->event_thread.mutex);
+    pthread_cond_destroy(&pdb->event_thread.cond);
+    return (-1);
+  }
+  /* start event thread */
+  pthread_t tid;
+  if (plugin_thread_create(&tid, NULL, ovs_event_worker, pdb,
+                           "utils_ovs:event") != 0) {
+    pthread_mutex_unlock(&pdb->event_thread.mutex);
+    pthread_mutex_destroy(&pdb->event_thread.mutex);
+    pthread_cond_destroy(&pdb->event_thread.cond);
+    return (-1);
+  }
+  pdb->event_thread.tid = tid;
+  return (0);
+}
+
+/* Destroy EVENT thread */
+static int ovs_db_event_thread_destroy(ovs_db_t *pdb) {
+  if (pdb->event_thread.tid < 0)
+    /* already destroyed */
+    return (0);
+  ovs_db_event_post(pdb, OVS_DB_EVENT_TERMINATE);
+  if (pthread_join(pdb->event_thread.tid, NULL) != 0)
+    return (-1);
+  /* Event thread always holds the thread mutex when
+   * performs some task (handles event) and releases it when
+   * while sleeping. Thus, if event thread exits, the mutex
+   * remains locked */
+  pthread_mutex_unlock(&pdb->event_thread.mutex);
+  pthread_mutex_destroy(&pdb->event_thread.mutex);
+  pthread_cond_destroy(&pdb->event_thread.cond);
+  pdb->event_thread.tid = -1;
+  return (0);
+}
+
+/* Initialize POLL thread */
+static int ovs_db_poll_thread_init(ovs_db_t *pdb) {
+  pdb->poll_thread.tid = -1;
+  /* init event thread mutex */
+  if (pthread_mutex_init(&pdb->poll_thread.mutex, NULL)) {
+    return (-1);
+  }
+  /* start poll thread */
+  pthread_t tid;
+  pdb->poll_thread.state = OVS_DB_POLL_STATE_RUNNING;
+  if (plugin_thread_create(&tid, NULL, ovs_poll_worker, pdb,
+                           "utils_ovs:poll") != 0) {
+    pthread_mutex_destroy(&pdb->poll_thread.mutex);
+    return (-1);
+  }
+  pdb->poll_thread.tid = tid;
+  return (0);
+}
+
+/* Destroy POLL thread */
+static int ovs_db_poll_thread_destroy(ovs_db_t *pdb) {
+  if (pdb->poll_thread.tid < 0)
+    /* already destroyed */
+    return (0);
+  /* change thread state */
+  pthread_mutex_lock(&pdb->poll_thread.mutex);
+  pdb->poll_thread.state = OVS_DB_POLL_STATE_EXITING;
+  pthread_mutex_unlock(&pdb->poll_thread.mutex);
+  /* join the thread */
+  if (pthread_join(pdb->poll_thread.tid, NULL) != 0)
+    return (-1);
+  pthread_mutex_destroy(&pdb->poll_thread.mutex);
+  pdb->poll_thread.tid = -1;
+  return (0);
+}
+
+/*
+ * Public OVS DB API implementation
+ */
+
+ovs_db_t *ovs_db_init(const char *node, const char *service,
+                      const char *unix_path, ovs_db_callback_t *cb) {
+  /* sanity check */
+  if (node == NULL || service == NULL || unix_path == NULL)
+    return (NULL);
+
+  /* allocate db data & fill it */
+  ovs_db_t *pdb = pdb = calloc(1, sizeof(*pdb));
+  if (pdb == NULL)
+    return (NULL);
+
+  /* store the OVS DB address */
+  sstrncpy(pdb->node, node, sizeof(pdb->node));
+  sstrncpy(pdb->service, service, sizeof(pdb->service));
+  sstrncpy(pdb->unix_path, unix_path, sizeof(pdb->unix_path));
+
+  /* setup OVS DB callbacks */
+  if (cb)
+    pdb->cb = *cb;
+
+  /* init OVS DB mutex attributes */
+  pthread_mutexattr_t mutex_attr;
+  if (pthread_mutexattr_init(&mutex_attr)) {
+    OVS_ERROR("OVS DB mutex attribute init failed");
+    sfree(pdb);
+    return (NULL);
+  }
+  /* set OVS DB mutex as recursive */
+  if (pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE)) {
+    OVS_ERROR("Failed to set OVS DB mutex as recursive");
+    pthread_mutexattr_destroy(&mutex_attr);
+    sfree(pdb);
+    return (NULL);
+  }
+  /* init OVS DB mutex */
+  if (pthread_mutex_init(&pdb->mutex, &mutex_attr)) {
+    OVS_ERROR("OVS DB mutex init failed");
+    pthread_mutexattr_destroy(&mutex_attr);
+    sfree(pdb);
+    return (NULL);
+  }
+  /* destroy mutex attributes */
+  pthread_mutexattr_destroy(&mutex_attr);
+
+  /* init event thread */
+  if (ovs_db_event_thread_init(pdb) < 0) {
+    ovs_db_destroy(pdb);
+    return (NULL);
+  }
+
+  /* init polling thread */
+  pdb->sock = -1;
+  if (ovs_db_poll_thread_init(pdb) < 0) {
+    ovs_db_destroy(pdb);
+    return (NULL);
+  }
+  return pdb;
+}
+
+int ovs_db_send_request(ovs_db_t *pdb, const char *method, const char *params,
+                        ovs_db_result_cb_t cb) {
+  int ret = 0;
+  yajl_gen_status yajl_gen_ret;
+  yajl_val jparams;
+  yajl_gen jgen;
+  ovs_callback_t *new_cb = NULL;
+  uint64_t uid;
+  char uid_buff[OVS_UID_STR_SIZE];
+  const char *req = NULL;
+  size_t req_len = 0;
+  struct timespec ts;
+
+  /* sanity check */
+  if (!pdb || !method || !params)
+    return (-1);
+
+  if ((jgen = yajl_gen_alloc(NULL)) == NULL)
+    return (-1);
+
+  /* try to parse params */
+  if ((jparams = yajl_tree_parse(params, NULL, 0)) == NULL) {
+    OVS_ERROR("params is not a JSON string");
+    yajl_gen_clear(jgen);
+    return (-1);
+  }
+
+  /* generate method field */
+  OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "method");
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, method);
+
+  /* generate params field */
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "params");
+  OVS_YAJL_CALL(ovs_yajl_gen_val, jgen, jparams);
+  yajl_tree_free(jparams);
+
+  /* generate id field */
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "id");
+  uid = ovs_uid_generate();
+  ssnprintf(uid_buff, sizeof(uid_buff), "%" PRIX64, uid);
+  OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_buff);
+
+  OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+
+  if (cb) {
+    /* register result callback */
+    if ((new_cb = calloc(1, sizeof(ovs_callback_t))) == NULL)
+      goto yajl_gen_failure;
+
+    /* add new callback to front */
+    sem_init(&new_cb->result.sync, 0, 0);
+    new_cb->result.call = cb;
+    new_cb->uid = uid;
+    ovs_db_callback_add(pdb, new_cb);
+  }
+
+  /* send the request */
+  OVS_YAJL_CALL(yajl_gen_get_buf, jgen, (const unsigned char **)&req, &req_len);
+  OVS_DEBUG("%s", req);
+  if (!ovs_db_data_send(pdb, req, req_len)) {
+    if (cb) {
+      /* wait for result */
+      clock_gettime(CLOCK_REALTIME, &ts);
+      ts.tv_sec += OVS_DB_SEND_REQ_TIMEOUT;
+      if (sem_timedwait(&new_cb->result.sync, &ts) < 0) {
+        OVS_ERROR("%s() no replay received within %d sec", __FUNCTION__,
+                  OVS_DB_SEND_REQ_TIMEOUT);
+        ret = (-1);
+      }
+    }
+  } else {
+    OVS_ERROR("ovs_db_data_send() failed");
+    ret = (-1);
+  }
+
+yajl_gen_failure:
+  if (new_cb) {
+    /* destroy callback */
+    sem_destroy(&new_cb->result.sync);
+    ovs_db_callback_remove(pdb, new_cb);
+  }
+
+  /* release memory */
+  yajl_gen_clear(jgen);
+  return (yajl_gen_ret != yajl_gen_status_ok) ? (-1) : ret;
+}
+
+int ovs_db_table_cb_register(ovs_db_t *pdb, const char *tb_name,
+                             const char **tb_column,
+                             ovs_db_table_cb_t update_cb,
+                             ovs_db_result_cb_t result_cb, unsigned int flags) {
+  yajl_gen jgen;
+  yajl_gen_status yajl_gen_ret;
+  ovs_callback_t *new_cb = NULL;
+  char uid_str[OVS_UID_STR_SIZE];
+  char *params;
+  size_t params_len;
+  int ovs_db_ret = 0;
+
+  /* sanity check */
+  if (pdb == NULL || tb_name == NULL || update_cb == NULL)
+    return (-1);
+
+  /* allocate new update callback */
+  if ((new_cb = calloc(1, sizeof(ovs_callback_t))) == NULL)
+    return (-1);
+
+  /* init YAJL generator */
+  if ((jgen = yajl_gen_alloc(NULL)) == NULL) {
+    sfree(new_cb);
+    return (-1);
+  }
+
+  /* add new callback to front */
+  new_cb->table.call = update_cb;
+  new_cb->uid = ovs_uid_generate();
+  ovs_db_callback_add(pdb, new_cb);
+
+  /* make update notification request
+   * [<db-name>, <json-value>, <monitor-requests>] */
+  OVS_YAJL_CALL(yajl_gen_array_open, jgen);
+  {
+    OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, OVS_DB_DEFAULT_DB_NAME);
+
+    /* uid string <json-value> */
+    ssnprintf(uid_str, sizeof(uid_str), "%" PRIX64, new_cb->uid);
+    OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, uid_str);
+
+    /* <monitor-requests> */
+    OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+    {
+      OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, tb_name);
+      OVS_YAJL_CALL(yajl_gen_array_open, jgen);
+      {
+        /* <monitor-request> */
+        OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+        {
+          if (tb_column) {
+            /* columns within the table to be monitored */
+            OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "columns");
+            OVS_YAJL_CALL(yajl_gen_array_open, jgen);
+            for (; *tb_column; tb_column++)
+              OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, *tb_column);
+            OVS_YAJL_CALL(yajl_gen_array_close, jgen);
+          }
+          /* specify select option */
+          OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "select");
+          {
+            OVS_YAJL_CALL(yajl_gen_map_open, jgen);
+            {
+              OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "initial");
+              OVS_YAJL_CALL(yajl_gen_bool, jgen,
+                            flags & OVS_DB_TABLE_CB_FLAG_INITIAL);
+              OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "insert");
+              OVS_YAJL_CALL(yajl_gen_bool, jgen,
+                            flags & OVS_DB_TABLE_CB_FLAG_INSERT);
+              OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "delete");
+              OVS_YAJL_CALL(yajl_gen_bool, jgen,
+                            flags & OVS_DB_TABLE_CB_FLAG_DELETE);
+              OVS_YAJL_CALL(ovs_yajl_gen_tstring, jgen, "modify");
+              OVS_YAJL_CALL(yajl_gen_bool, jgen,
+                            flags & OVS_DB_TABLE_CB_FLAG_MODIFY);
+            }
+            OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+          }
+        }
+        OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+      }
+      OVS_YAJL_CALL(yajl_gen_array_close, jgen);
+    }
+    OVS_YAJL_CALL(yajl_gen_map_close, jgen);
+  }
+  OVS_YAJL_CALL(yajl_gen_array_close, jgen);
+
+  /* make a request to subscribe to given table */
+  OVS_YAJL_CALL(yajl_gen_get_buf, jgen, (const unsigned char **)&params,
+                &params_len);
+  if (ovs_db_send_request(pdb, "monitor", params, result_cb) < 0) {
+    OVS_ERROR("Failed to subscribe to \"%s\" table", tb_name);
+    ovs_db_ret = (-1);
+  }
+
+yajl_gen_failure:
+  /* release memory */
+  yajl_gen_clear(jgen);
+  return ovs_db_ret;
+}
+
+int ovs_db_destroy(ovs_db_t *pdb) {
+  int ovs_db_ret = 0;
+  int ret = 0;
+
+  /* sanity check */
+  if (pdb == NULL)
+    return (-1);
+
+  /* try to lock the structure before releasing */
+  if ((ret = pthread_mutex_lock(&pdb->mutex))) {
+    OVS_ERROR("pthread_mutex_lock() DB mutex lock failed (%d)", ret);
+    return (-1);
+  }
+
+  /* stop poll thread */
+  if (ovs_db_event_thread_destroy(pdb) < 0) {
+    OVS_ERROR("destroy poll thread failed");
+    ovs_db_ret = (-1);
+  }
+
+  /* stop event thread */
+  if (ovs_db_poll_thread_destroy(pdb) < 0) {
+    OVS_ERROR("stop event thread failed");
+    ovs_db_ret = (-1);
+  }
+
+  /* unsubscribe callbacks */
+  ovs_db_callback_remove_all(pdb);
+
+  /* close connection */
+  if (pdb->sock >= 0)
+    close(pdb->sock);
+
+  /* release DB handler */
+  pthread_mutex_unlock(&pdb->mutex);
+  pthread_mutex_destroy(&pdb->mutex);
+  sfree(pdb);
+  return ovs_db_ret;
+}
+
+/*
+ * Public OVS utils API implementation
+ */
+
+/* Get YAJL value by key from YAJL dictionary
+ *
+ * EXAMPLE:
+ *  {
+ *    "key_a" : <YAJL return value>
+ *    "key_b" : <YAJL return value>
+ *  }
+ */
+yajl_val ovs_utils_get_value_by_key(yajl_val jval, const char *key) {
+  const char *obj_key = NULL;
+
+  /* check params */
+  if (!YAJL_IS_OBJECT(jval) || (key == NULL))
+    return NULL;
+
+  /* find a value by key */
+  for (int i = 0; i < YAJL_GET_OBJECT(jval)->len; i++) {
+    obj_key = YAJL_GET_OBJECT(jval)->keys[i];
+    if (strcmp(obj_key, key) == 0)
+      return YAJL_GET_OBJECT(jval)->values[i];
+  }
+
+  return NULL;
+}
+
+/* Get OVS DB map value by given map key
+ *
+ * FROM RFC7047:
+ *
+ *   <pair>
+ *     A 2-element JSON array that represents a pair within a database
+ *     map.  The first element is an <atom> that represents the key, and
+ *     the second element is an <atom> that represents the value.
+ *
+ *   <map>
+ *     A 2-element JSON array that represents a database map value.  The
+ *     first element of the array must be the string "map", and the
+ *     second element must be an array of zero or more <pair>s giving the
+ *     values in the map.  All of the <pair>s must have the same key and
+ *     value types.
+ *
+ * EXAMPLE:
+ *  [
+ *    "map", [
+ *             [ "key_a", <YAJL value>], [ "key_b", <YAJL value>], ...
+ *           ]
+ *  ]
+ */
+yajl_val ovs_utils_get_map_value(yajl_val jval, const char *key) {
+  size_t map_len = 0;
+  size_t array_len = 0;
+  yajl_val *map_values = NULL;
+  yajl_val *array_values = NULL;
+  const char *str_val = NULL;
+
+  /* check YAJL array */
+  if (!YAJL_IS_ARRAY(jval) || (key == NULL))
+    return NULL;
+
+  /* check a database map value (2-element, first one should be a string */
+  array_len = YAJL_GET_ARRAY(jval)->len;
+  array_values = YAJL_GET_ARRAY(jval)->values;
+  if ((array_len != 2) || (!YAJL_IS_STRING(array_values[0])) ||
+      (!YAJL_IS_ARRAY(array_values[1])))
+    return NULL;
+
+  /* check first element of the array */
+  str_val = YAJL_GET_STRING(array_values[0]);
+  if (strcmp("map", str_val) != 0)
+    return NULL;
+
+  /* try to find map value by map key */
+  map_len = YAJL_GET_ARRAY(array_values[1])->len;
+  map_values = YAJL_GET_ARRAY(array_values[1])->values;
+  for (int i = 0; i < map_len; i++) {
+    /* check YAJL array */
+    if (!YAJL_IS_ARRAY(map_values[i]))
+      break;
+
+    /* check a database pair value (2-element, first one represents a key
+     * and it should be a string in our case */
+    array_len = YAJL_GET_ARRAY(map_values[i])->len;
+    array_values = YAJL_GET_ARRAY(map_values[i])->values;
+    if ((array_len != 2) || (!YAJL_IS_STRING(array_values[0])))
+      break;
+
+    /* return map value if given key equals map key */
+    str_val = YAJL_GET_STRING(array_values[0]);
+    if (strcmp(key, str_val) == 0)
+      return array_values[1];
+  }
+  return NULL;
+}
diff --git a/src/utils_ovs.h b/src/utils_ovs.h
new file mode 100644 (file)
index 0000000..52c2f91
--- /dev/null
@@ -0,0 +1,236 @@
+/**
+ * collectd - src/utils_ovs.h
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Volodymyr Mytnyk <volodymyrx.mytnyk@intel.com>
+ *
+ * Description:
+ *  The OVS util module provides the following features:
+ *   - Implements the OVS DB communication transport specified
+ *     by RFC7047:
+ *     * Connect/disconnect to OVS DB;
+ *     * Recovery mechanism in case of OVS DB connection lost;
+ *     * Subscription mechanism to OVS DB table update events
+ *       (insert/modify/delete);
+ *     * Send custom JSON request to OVS DB (poll table data, etc.)
+ *     * Handling of echo request from OVS DB server to verify the
+ *       liveness of the connection.
+ *   - Provides YAJL helpers functions.
+ *
+ *  OVS DB API User Guide:
+ *    All OVS DB function/structure names begins from 'ovs_db_*' prefix. To
+ *   start using OVS DB API, client (plugin) should initialize the OVS DB
+ *   object (`ovs_db_t') by calling `ovs_db_init' function. It initializes
+ *   internal data and creates two main workers (threads). The result of the
+ *   function is a pointer to new OVS DB object which can be used by other
+ *   OVS DB API later and must be released by `ovs_db_destroy' function if
+ *   the object isn't needed anymore.
+ *    Once OVS DB API is initialized, the `init_cb' callback is called if
+ *   the connection to OVS DB has been established. This callback is called
+ *   every time the OVS DB is reconnected. So, if the client registers table
+ *   update event callbacks or does any other OVS DB setup that can be lost
+ *   after OVS DB reconnecting, it should be done in `init_cb' callback.
+ *    The `ovs_db_table_cb_register` function is used to register OVS DB
+ *   table update event callback and receive the table update notification
+ *   when requested event occurs (registered callback is called). See
+ *   function API for more info.
+ *    To send custom JSON-RPC request to OVS DB, the `ovs_db_send_request'
+ *   function is used. Please note, that connection to OVS DB should be
+ *   established otherwise the function will return error.
+ *    To verify the liveness of established connection, the OVS DB server
+ *   sends echo request to the client with a given interval. The OVS utils
+ *   takes care about this request and handles it properly.
+ **/
+
+#ifndef UTILS_OVS_H
+#define UTILS_OVS_H
+
+#include <yajl/yajl_gen.h>
+#include <yajl/yajl_tree.h>
+
+/* Forward declaration */
+typedef struct ovs_db_s ovs_db_t;
+
+/* OVS DB callback type declaration */
+typedef void (*ovs_db_table_cb_t)(yajl_val jupdates);
+typedef void (*ovs_db_result_cb_t)(yajl_val jresult, yajl_val jerror);
+
+/* OVS DB structures */
+struct ovs_db_callback_s {
+  /*
+   * This callback is called when OVS DB connection
+   * has been established and ready to use. Client
+   * can use this callback to configure OVS DB, e.g.
+   * to subscribe to table update notification or poll
+   * some OVS DB data. This field can be NULL.
+   */
+  void (*post_conn_init)(ovs_db_t *pdb);
+  /*
+   * This callback is called when OVS DB connection
+   * has been lost. This field can be NULL.
+   */
+  void (*post_conn_terminate)(void);
+};
+typedef struct ovs_db_callback_s ovs_db_callback_t;
+
+/* OVS DB defines */
+#define OVS_DB_ADDR_NODE_SIZE 256
+#define OVS_DB_ADDR_SERVICE_SIZE 128
+#define OVS_DB_ADDR_UNIX_SIZE 108
+
+/* OVS DB prototypes */
+
+/*
+ * NAME
+ *   ovs_db_init
+ *
+ * DESCRIPTION
+ *   Initialize OVS DB internal data. The `ovs_db_destroy' function
+ *   shall destroy the returned object.
+ *
+ * PARAMETERS
+ *   `node'        OVS DB Address.
+ *   `service'     OVS DB service name.
+ *   `unix'        OVS DB unix socket path.
+ *   `cb'          OVS DB callbacks.
+ *
+ * RETURN VALUE
+ *   New ovs_db_t object upon success or NULL if an error occurred.
+ */
+ovs_db_t *ovs_db_init(const char *node, const char *service,
+                      const char *unix_path, ovs_db_callback_t *cb);
+
+/*
+ * NAME
+ *   ovs_db_destroy
+ *
+ * DESCRIPTION
+ *   Destroy OVS DB object referenced by `pdb'.
+ *
+ * PARAMETERS
+ *   `pdb'         Pointer to OVS DB object.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if an error occurred.
+ */
+int ovs_db_destroy(ovs_db_t *pdb);
+
+/*
+ * NAME
+ *   ovs_db_send_request
+ *
+ * DESCRIPTION
+ *   Send JSON request to OVS DB server.
+ *
+ * PARAMETERS
+ *   `pdb'         Pointer to OVS DB object.
+ *   `method'      Request method name.
+ *   `params'      Method params to be sent (JSON value as a string).
+ *   `cb'          Result callback of the request. If NULL, the request
+ *                 is sent asynchronously.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if an error occurred.
+ */
+int ovs_db_send_request(ovs_db_t *pdb, const char *method, const char *params,
+                        ovs_db_result_cb_t cb);
+
+/* callback types */
+#define OVS_DB_TABLE_CB_FLAG_INITIAL 0x01U
+#define OVS_DB_TABLE_CB_FLAG_INSERT 0x02U
+#define OVS_DB_TABLE_CB_FLAG_DELETE 0x04U
+#define OVS_DB_TABLE_CB_FLAG_MODIFY 0x08U
+#define OVS_DB_TABLE_CB_FLAG_ALL 0x0FU
+
+/*
+ * NAME
+ *   ovs_db_table_cb_register
+ *
+ * DESCRIPTION
+ *   Subscribe a callback on OVS DB table event. It allows to
+ *   receive notifications (`update_cb' callback is called) of
+ *   changes to requested table.
+ *
+ * PARAMETERS
+ *   `pdb'         Pointer to OVS DB object.
+ *   `tb_name'     OVS DB Table name to be monitored.
+ *   `tb_column'   OVS DB Table columns to be monitored. Last
+ *                 element in the array should be NULL.
+ *   `update_cb'   Callback function that is called when
+ *                 requested table columns are changed.
+ *   `cb'          Result callback of the request. If NULL, the call
+ *                 becomes asynchronous.
+ *                 Useful, if OVS_DB_TABLE_CB_FLAG_INITIAL is set.
+ *   `flags'       Bit mask of:
+ *                   OVS_DB_TABLE_CB_FLAG_INITIAL Receive initial values in
+ *                                               result callback.
+ *                   OVS_DB_TABLE_CB_FLAG_INSERT  Receive table insert events.
+ *                   OVS_DB_TABLE_CB_FLAG_DELETE  Receive table remove events.
+ *                   OVS_DB_TABLE_CB_FLAG_MODIFY  Receive table update events.
+ *                   OVS_DB_TABLE_CB_FLAG_ALL     Receive all events.
+ *
+ * RETURN VALUE
+ *   Zero upon success or non-zero if an error occurred.
+ */
+int ovs_db_table_cb_register(ovs_db_t *pdb, const char *tb_name,
+                             const char **tb_column,
+                             ovs_db_table_cb_t update_cb,
+                             ovs_db_result_cb_t result_cb, unsigned int flags);
+
+/*
+ * OVS utils API
+ */
+
+/*
+ * NAME
+ *   ovs_utils_get_value_by_key
+ *
+ * DESCRIPTION
+ *   Get YAJL value by object name.
+ *
+ * PARAMETERS
+ *   `jval'        YAJL object value.
+ *   `key'         Object key name.
+ *
+ * RETURN VALUE
+ *   YAJL value upon success or NULL if key not found.
+ */
+yajl_val ovs_utils_get_value_by_key(yajl_val jval, const char *key);
+
+/*
+ * NAME
+ *   ovs_utils_get_map_value
+ *
+ * DESCRIPTION
+ *   Get OVS DB map value by given map key (rfc7047, "Notation" section).
+ *
+ * PARAMETERS
+ *   `jval'        A 2-element YAJL array that represents a OVS DB map value.
+ *   `key'         OVS DB map key name.
+ *
+ * RETURN VALUE
+ *   YAJL value upon success or NULL if key not found.
+ */
+yajl_val ovs_utils_get_map_value(yajl_val jval, const char *key);
+
+#endif
index d3012d9..830db51 100644 (file)
@@ -504,6 +504,29 @@ static int lv_config(const char *key, const char *value) {
   return -1;
 }
 
+static int lv_connect(void) {
+  if (conn == NULL) {
+    /* `conn_string == NULL' is acceptable. */
+    conn = virConnectOpenReadOnly(conn_string);
+    if (conn == NULL) {
+      c_complain(LOG_ERR, &conn_complain,
+                 PLUGIN_NAME " plugin: Unable to connect: "
+                             "virConnectOpenReadOnly failed.");
+      return -1;
+    }
+  }
+  c_release(LOG_NOTICE, &conn_complain,
+            PLUGIN_NAME " plugin: Connection established.");
+  return 0;
+}
+
+static void lv_disconnect(void) {
+  if (conn != NULL)
+    virConnectClose(conn);
+  conn = NULL;
+  WARNING(PLUGIN_NAME " plugin: closed connection to libvirt");
+}
+
 static int lv_read(user_data_t *ud) {
   time_t t;
   struct lv_read_instance *inst = NULL;
@@ -517,18 +540,10 @@ static int lv_read(user_data_t *ud) {
   inst = ud->data;
   state = &inst->read_state;
 
-  if (inst->id == 0 && conn == NULL) {
-    /* `conn_string == NULL' is acceptable. */
-    conn = virConnectOpenReadOnly(conn_string);
-    if (conn == NULL) {
-      c_complain(LOG_ERR, &conn_complain,
-                 PLUGIN_NAME " plugin: Unable to connect: "
-                             "virConnectOpenReadOnly failed.");
+  if (inst->id == 0) {
+    if (lv_connect() < 0)
       return -1;
-    }
   }
-  c_release(LOG_NOTICE, &conn_complain,
-            PLUGIN_NAME " plugin: Connection established.");
 
   time(&t);
 
@@ -536,9 +551,8 @@ static int lv_read(user_data_t *ud) {
   if ((last_refresh == (time_t)0) ||
       ((interval > 0) && ((last_refresh + interval) <= t))) {
     if (refresh_lists(inst) != 0) {
-      if (conn != NULL)
-        virConnectClose(conn);
-      conn = NULL;
+      if (inst->id == 0)
+        lv_disconnect();
       return -1;
     }
     last_refresh = t;
@@ -732,6 +746,9 @@ static int lv_init(void) {
   if (virInitialize() != 0)
     return -1;
 
+  if (lv_connect() != 0)
+    return -1;
+
   DEBUG(PLUGIN_NAME " plugin: starting %i instances", nr_instances);
 
   for (int i = 0; i < nr_instances; ++i)
@@ -919,10 +936,10 @@ static int refresh_lists(struct lv_read_instance *inst) {
       }
 
       /* Block devices. */
-      char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
+      const char *bd_xmlpath = "/domain/devices/disk/target[@dev]";
       if (blockdevice_format == source)
         bd_xmlpath = "/domain/devices/disk/source[@dev]";
-      xpath_obj = xmlXPathEval((xmlChar *)bd_xmlpath, xpath_ctx);
+      xpath_obj = xmlXPathEval((const xmlChar *)bd_xmlpath, xpath_ctx);
 
       if (xpath_obj == NULL || xpath_obj->type != XPATH_NODESET ||
           xpath_obj->nodesetval == NULL)
@@ -1161,9 +1178,7 @@ static int lv_shutdown(void) {
     lv_fini_instance(i);
   }
 
-  if (conn != NULL)
-    virConnectClose(conn);
-  conn = NULL;
+  lv_disconnect();
 
   ignorelist_free(il_domains);
   il_domains = NULL;
index 6dee98a..61c43fe 100644 (file)
@@ -694,8 +694,10 @@ metric_family_get(data_set_t const *ds, value_list_t const *vl, size_t ds_index,
     return fam;
   }
 
-  if (!allocate)
+  if (!allocate) {
+    sfree(name);
     return NULL;
+  }
 
   fam = metric_family_create(name, ds, vl, ds_index);
   if (fam == NULL) {
index 429c159..99c8427 100644 (file)
@@ -45,8 +45,8 @@
 
 #include "common.h"
 #include "plugin.h"
-
 #include "utils_cache.h"
+#include "utils_random.h"
 
 #include <netdb.h>
 
@@ -71,6 +71,8 @@
  * Private variables
  */
 struct wt_callback {
+  struct addrinfo *ai;
+  cdtime_t ai_last_update;
   int sock_fd;
 
   char *node;
@@ -86,8 +88,15 @@ struct wt_callback {
   cdtime_t send_buf_init_time;
 
   pthread_mutex_t send_lock;
+
+  _Bool connect_failed_log_enabled;
+  int connect_dns_failed_attempts_remaining;
+  cdtime_t next_random_ttl;
 };
 
+static cdtime_t resolve_interval = 0;
+static cdtime_t resolve_jitter = 0;
+
 /*
  * Functions
  */
@@ -144,9 +153,16 @@ static int wt_flush_nolock(cdtime_t timeout, struct wt_callback *cb) {
   return status;
 }
 
+static cdtime_t new_random_ttl() {
+  if (resolve_jitter == 0)
+    return 0;
+
+  return (cdtime_t)cdrand_range(0, (long)resolve_jitter);
+}
+
 static int wt_callback_init(struct wt_callback *cb) {
-  struct addrinfo *ai_list;
   int status;
+  cdtime_t now;
 
   const char *node = cb->node ? cb->node : WT_DEFAULT_NODE;
   const char *service = cb->service ? cb->service : WT_DEFAULT_SERVICE;
@@ -154,28 +170,68 @@ static int wt_callback_init(struct wt_callback *cb) {
   if (cb->sock_fd > 0)
     return 0;
 
-  struct addrinfo ai_hints = {.ai_family = AF_UNSPEC,
-                              .ai_flags = AI_ADDRCONFIG,
-                              .ai_socktype = SOCK_STREAM};
+  now = cdtime();
+  if (cb->ai) {
+    /* When we are here, we still have the IP in cache.
+     * If we have remaining attempts without calling the DNS, we update the
+     * last_update date so we keep the info until next time.
+     * If there is no more attempts, we need to flush the cache.
+     */
+
+    if ((cb->ai_last_update + resolve_interval + cb->next_random_ttl) < now) {
+      cb->next_random_ttl = new_random_ttl();
+      if (cb->connect_dns_failed_attempts_remaining > 0) {
+        /* Warning : this is run under send_lock mutex.
+         * This is why we do not use another mutex here.
+         * */
+        cb->ai_last_update = now;
+        cb->connect_dns_failed_attempts_remaining--;
+      } else {
+        freeaddrinfo(cb->ai);
+        cb->ai = NULL;
+      }
+    }
+  }
 
-  status = getaddrinfo(node, service, &ai_hints, &ai_list);
-  if (status != 0) {
-    ERROR("write_tsdb plugin: getaddrinfo (%s, %s) failed: %s", node, service,
-          gai_strerror(status));
-    return -1;
+  if (cb->ai == NULL) {
+    if ((cb->ai_last_update + resolve_interval + cb->next_random_ttl) >= now) {
+      DEBUG("write_tsdb plugin: too many getaddrinfo(%s, %s) failures", node,
+            service);
+      return (-1);
+    }
+    cb->ai_last_update = now;
+    cb->next_random_ttl = new_random_ttl();
+
+    struct addrinfo ai_hints = {
+        .ai_family = AF_UNSPEC,
+        .ai_flags = AI_ADDRCONFIG,
+        .ai_socktype = SOCK_STREAM,
+    };
+
+    status = getaddrinfo(node, service, &ai_hints, &cb->ai);
+    if (status != 0) {
+      if (cb->ai) {
+        freeaddrinfo(cb->ai);
+        cb->ai = NULL;
+      }
+      if (cb->connect_failed_log_enabled) {
+        ERROR("write_tsdb plugin: getaddrinfo(%s, %s) failed: %s", node,
+              service, gai_strerror(status));
+        cb->connect_failed_log_enabled = 0;
+      }
+      return -1;
+    }
   }
 
-  assert(ai_list != NULL);
-  for (struct addrinfo *ai_ptr = ai_list; ai_ptr != NULL;
-       ai_ptr = ai_ptr->ai_next) {
-    cb->sock_fd =
-        socket(ai_ptr->ai_family, ai_ptr->ai_socktype, ai_ptr->ai_protocol);
+  assert(cb->ai != NULL);
+  for (struct addrinfo *ai = cb->ai; ai != NULL; ai = ai->ai_next) {
+    cb->sock_fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     if (cb->sock_fd < 0)
       continue;
 
     set_sock_opts(cb->sock_fd);
 
-    status = connect(cb->sock_fd, ai_ptr->ai_addr, ai_ptr->ai_addrlen);
+    status = connect(cb->sock_fd, ai->ai_addr, ai->ai_addrlen);
     if (status != 0) {
       close(cb->sock_fd);
       cb->sock_fd = -1;
@@ -185,8 +241,6 @@ static int wt_callback_init(struct wt_callback *cb) {
     break;
   }
 
-  freeaddrinfo(ai_list);
-
   if (cb->sock_fd < 0) {
     char errbuf[1024];
     ERROR("write_tsdb plugin: Connecting to %s:%s failed. "
@@ -195,6 +249,12 @@ static int wt_callback_init(struct wt_callback *cb) {
     return -1;
   }
 
+  if (0 == cb->connect_failed_log_enabled) {
+    WARNING("write_tsdb plugin: Connecting to %s:%s succeeded.", node, service);
+    cb->connect_failed_log_enabled = 1;
+  }
+  cb->connect_dns_failed_attempts_remaining = 1;
+
   wt_reset_buffer(cb);
 
   return 0;
@@ -522,10 +582,8 @@ static int wt_config_tsd(oconfig_item_t *ci) {
     return -1;
   }
   cb->sock_fd = -1;
-  cb->node = NULL;
-  cb->service = NULL;
-  cb->host_tags = NULL;
-  cb->store_rates = 0;
+  cb->connect_failed_log_enabled = 1;
+  cb->next_random_ttl = new_random_ttl();
 
   pthread_mutex_init(&cb->send_lock, NULL);
 
@@ -564,11 +622,18 @@ static int wt_config_tsd(oconfig_item_t *ci) {
 }
 
 static int wt_config(oconfig_item_t *ci) {
+  if ((resolve_interval == 0) && (resolve_jitter == 0))
+    resolve_interval = resolve_jitter = plugin_get_interval();
+
   for (int i = 0; i < ci->children_num; i++) {
     oconfig_item_t *child = ci->children + i;
 
     if (strcasecmp("Node", child->key) == 0)
       wt_config_tsd(child);
+    else if (strcasecmp("ResolveInterval", child->key) == 0)
+      cf_util_get_cdtime(child, &resolve_interval);
+    else if (strcasecmp("ResolveJitter", child->key) == 0)
+      cf_util_get_cdtime(child, &resolve_jitter);
     else {
       ERROR("write_tsdb plugin: Invalid configuration "
             "option: %s.",
index 56daf44..2083ec3 100755 (executable)
@@ -1,6 +1,6 @@
 #!/bin/sh
 
-DEFAULT_VERSION="5.6.2.git"
+DEFAULT_VERSION="5.7.0.git"
 
 if [ -d .git ]; then
        VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"