From: Ruben Kerkhof Date: Tue, 28 Feb 2017 18:18:05 +0000 (+0100) Subject: Merge pull request #2137 from maryamtahhan/feat_ovs_stats X-Git-Tag: collectd-5.8.0~221 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=79a94204db8de144bf5bd84159afde444df9e0a4;hp=fa42219b60c054b3366cb977e953077fda609961 Merge pull request #2137 from maryamtahhan/feat_ovs_stats ovs_stats: Implement OVS statistics plugin. --- diff --git a/AUTHORS b/AUTHORS index 8962e775..d866c700 100644 --- a/AUTHORS +++ b/AUTHORS @@ -294,6 +294,9 @@ Sjoerd van der Berg Stefan Hacker - teamspeak2 plugin. +Steven Bell + - nut plugin. + Sven Trenkel - netapp plugin. - python plugin. diff --git a/ChangeLog b/ChangeLog index db0b0621..9f1b639f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2017-01-23, Version 5.7.1 + * collectd: Handling of boolean configuration options has been unified. + Thanks to Sebastian Harl. #2083, #2098 + * collectd: Reporting of internal statistics has been fixed. Thanks to + Florian Forster. #2108 + * collectd, various plugins: Bugs and issues reported by scan-build and + coverity-scan have been fixed. Thanks to Ruben Kerkhof and Florian + Forster. + * Build system: Parallel build have been fixed. Thanks to Ruben Kerkhof. + #2110 + * DPDKStat plugin: Portability issues and a double-close bug have been + fixed. Thanks to Ruben Kerkhof and Marc Fournier. + * Intel RDT plugin: A check for the libpqos library version has been + added. Thanks to Serhiy Pshyk. + * NetApp plugin: Compilation problems have been corrected. Thanks to + Florian Forster. #2120 + * Write Prometheus plugin: A memory leak has been fixed. Thanks to Ruben + Kerkhof. + 2016-12-12, Version 5.7.0 * Documentation: The Turbostat plugin section has been improved. Thanks to Florian Forster diff --git a/Makefile.am b/Makefile.am index 4f479e86..c0334723 100644 --- a/Makefile.am +++ b/Makefile.am @@ -609,6 +609,7 @@ if BUILD_PLUGIN_CHRONY pkglib_LTLIBRARIES += chrony.la chrony_la_SOURCES = src/chrony.c chrony_la_LDFLAGS = $(PLUGIN_LDFLAGS) +chrony_la_LIBADD = -lm endif if BUILD_PLUGIN_CONNTRACK @@ -765,6 +766,14 @@ dns_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(BUILD_WITH_LIBPCAP_LDFLAGS) dns_la_LIBADD = $(BUILD_WITH_LIBPCAP_LIBS) endif +if BUILD_PLUGIN_DPDKEVENTS +pkglib_LTLIBRARIES += dpdkevents.la +dpdkevents_la_SOURCES = src/dpdkevents.c src/utils_dpdk.c src/utils_dpdk.h +dpdkevents_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBDPDK_CPPFLAGS) +dpdkevents_la_LDFLAGS = $(PLUGIN_LDFLAGS) $(LIBDPDK_LDFLAGS) +dpdkevents_la_LIBADD = -ldpdk +endif + if BUILD_PLUGIN_DPDKSTAT pkglib_LTLIBRARIES += dpdkstat.la dpdkstat_la_SOURCES = src/dpdkstat.c src/utils_dpdk.c src/utils_dpdk.h @@ -1626,7 +1635,7 @@ if BUILD_PLUGIN_UNIXSOCK pkglib_LTLIBRARIES += unixsock.la unixsock_la_SOURCES = src/unixsock.c unixsock_la_LDFLAGS = $(PLUGIN_LDFLAGS) -unixsock_la_LIBS = libcmds.la +unixsock_la_LIBADD = libcmds.la endif if BUILD_PLUGIN_UPTIME diff --git a/bindings/java/org/collectd/java/GenericJMXConfValue.java b/bindings/java/org/collectd/java/GenericJMXConfValue.java index 63b76282..6d3d688e 100644 --- a/bindings/java/org/collectd/java/GenericJMXConfValue.java +++ b/bindings/java/org/collectd/java/GenericJMXConfValue.java @@ -30,6 +30,8 @@ import java.util.Arrays; import java.util.List; import java.util.Collection; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.Iterator; import java.util.ArrayList; @@ -128,6 +130,14 @@ class GenericJMXConfValue { return (BigInteger.ZERO.add ((BigInteger) obj)); } + else if (obj instanceof AtomicInteger) + { + return (new Integer(((AtomicInteger) obj).get())); + } + else if (obj instanceof AtomicLong) + { + return (new Long(((AtomicLong) obj).get())); + } return (null); } /* }}} Number genericObjectToNumber */ diff --git a/configure.ac b/configure.ac index 4d560152..63cfca77 100644 --- a/configure.ac +++ b/configure.ac @@ -585,14 +585,14 @@ if test "x$ac_system" = "xLinux"; then ) if test "x$have_capability" = "xyes"; then - AC_CHECK_LIB([cap], [cap_get_bound], + AC_CHECK_LIB([cap], [cap_get_proc], [have_capability="yes"], - [have_capability="no (cap_get_bound() not found)"] + [have_capability="no (cap_get_proc() not found)"] ) fi if test "x$have_capability" = "xyes"; then - AC_DEFINE([HAVE_CAPABILITY], [1], [Define to 1 if you have cap_get_bound() (-lcap).]) + AC_DEFINE([HAVE_CAPABILITY], [1], [Define to 1 if you have cap_get_proc() (-lcap).]) fi else @@ -2700,30 +2700,46 @@ AC_ARG_VAR([LIBDPDK_LDFLAGS], [Linker flags for libdpdk]) AC_ARG_WITH([libdpdk], [AS_HELP_STRING([--without-libdpdk], [Disable libdpdk.])]) -if test "x$with_libdpdk" != "xno" -then - if test "x$LIBDPDK_CPPFLAGS" = "x" - then - LIBDPDK_CPPFLAGS="-I/usr/include/dpdk" - fi - SAVE_CPPFLAGS="$CPPFLAGS" - CPPFLAGS="$LIBDPDK_CPPFLAGS $CPPFLAGS" - AC_CHECK_HEADERS([rte_config.h], - [with_libdpdk="yes"], - [with_libdpdk="no (rte_config.h not found)"] - ) - CPPFLAGS="$SAVE_CPPFLAGS" +if test "x$with_libdpdk" != "xno"; then + if test "x$LIBDPDK_CPPFLAGS" = "x"; then + LIBDPDK_CPPFLAGS="-I/usr/include/dpdk" + fi + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$LIBDPDK_CPPFLAGS $CPPFLAGS" + AC_CHECK_HEADERS([rte_config.h], + [ + with_libdpdk="yes" + AC_COMPILE_IFELSE( + [ + AC_LANG_PROGRAM( + [[ + #include + #if RTE_VERSION < RTE_VERSION_NUM(16,7,0,0) + #error "required DPDK >= 16.07" + #endif + ]], + [[ + return 0; + ]] + ) + ], + [dpdk_keepalive="yes"], + [dpdk_keepalive="no (DPDK version < 16.07)"] + ) + ], + [with_libdpdk="no (rte_config.h not found)"] + ) + CPPFLAGS="$SAVE_CPPFLAGS" fi -if test "x$with_libdpdk" = "xyes" -then - SAVE_LDFLAGS="$LDFLAGS" - LDFLAGS="$LIBDPDK_LDFLAGS $LDFLAGS" - AC_CHECK_LIB([dpdk], [rte_eal_init], - [with_libdpdk="yes"], - [with_libdpdk="no (symbol 'rte_eal_init' not found)"] - ) - LDFLAGS="$SAVE_LDFLAGS" +if test "x$with_libdpdk" = "xyes"; then + SAVE_LDFLAGS="$LDFLAGS" + LDFLAGS="$LIBDPDK_LDFLAGS $LDFLAGS" + AC_CHECK_LIB([dpdk], [rte_eal_init], + [with_libdpdk="yes"], + [with_libdpdk="no (symbol 'rte_eal_init' not found)"] + ) + LDFLAGS="$SAVE_LDFLAGS" fi # }}} @@ -4225,6 +4241,16 @@ then fi if test "x$with_libpqos" = "xyes" then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags" + AC_RUN_IFELSE([AC_LANG_PROGRAM( + [[#include ]], + [[return !(PQOS_VERSION >= 106)]])], + [with_libpqos="yes"], [with_libpqos="no (pqos library version 1.06 or higher is required)"]) + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libpqos" = "xyes" +then BUILD_WITH_LIBPQOS_CPPFLAGS="$with_libpqos_cppflags" BUILD_WITH_LIBPQOS_LDFLAGS="$with_libpqos_ldflags" BUILD_WITH_LIBPQOS_LIBS="-lpqos" @@ -5176,6 +5202,11 @@ if test "x$with_libupsclient" = "xyes"; then [with_libupsclient="no (symbol upscli_connect not found)"] ) + AC_CHECK_LIB([upsclient], [upscli_init], + [AC_DEFINE([WITH_UPSCLIENT_27], [1], [At least version 2-7])], + [] + ) + LDFLAGS="$SAVE_LDFLAGS" fi @@ -5871,6 +5902,7 @@ plugin_curl_xml="no" plugin_df="no" plugin_disk="no" plugin_drbd="no" +plugin_dpdkevents="no" plugin_dpdkstat="no" plugin_entropy="no" plugin_ethstat="no" @@ -6223,6 +6255,7 @@ fi if test "x$with_libdpdk" = "xyes" then + plugin_dpdkevents="$dpdk_keepalive" plugin_dpdkstat="yes" fi @@ -6271,6 +6304,7 @@ AC_PLUGIN([dbi], [$with_libdbi], [General database st AC_PLUGIN([df], [$plugin_df], [Filesystem usage statistics]) AC_PLUGIN([disk], [$plugin_disk], [Disk usage statistics]) AC_PLUGIN([dns], [$with_libpcap], [DNS traffic analysis]) +AC_PLUGIN([dpdkevents], [$plugin_dpdkevents], [Events from DPDK]) AC_PLUGIN([dpdkstat], [$plugin_dpdkstat], [Stats from DPDK]) AC_PLUGIN([drbd], [$plugin_drbd], [DRBD statistics]) AC_PLUGIN([email], [yes], [EMail statistics]) @@ -6697,6 +6731,7 @@ AC_MSG_RESULT([ dbi . . . . . . . . . $enable_dbi]) AC_MSG_RESULT([ df . . . . . . . . . $enable_df]) AC_MSG_RESULT([ disk . . . . . . . . $enable_disk]) AC_MSG_RESULT([ dns . . . . . . . . . $enable_dns]) +AC_MSG_RESULT([ dpdkevents. . . . . . $enable_dpdkevents]) AC_MSG_RESULT([ dpdkstat . . . . . . $enable_dpdkstat]) AC_MSG_RESULT([ drbd . . . . . . . . $enable_drbd]) AC_MSG_RESULT([ email . . . . . . . . $enable_email]) diff --git a/contrib/redhat/collectd.spec b/contrib/redhat/collectd.spec index 8726d7c6..451589d1 100644 --- a/contrib/redhat/collectd.spec +++ b/contrib/redhat/collectd.spec @@ -152,6 +152,7 @@ %define with_write_log 0%{!?_without_write_log:1} %define with_write_prometheus 0%{!?_without_write_prometheus:1} %define with_write_redis 0%{!?_without_write_redis:1} +%define with_write_riemann 0%{!?_without_write_riemann:1} %define with_write_sensu 0%{!?_without_write_sensu:1} %define with_write_tsdb 0%{!?_without_write_tsdb:1} %define with_xmms 0%{!?_without_xmms:0%{?_has_xmms}} @@ -197,8 +198,6 @@ %define with_write_kafka 0%{!?_without_write_kafka:0} # plugin write_mongodb disabled, requires libmongoc %define with_write_mongodb 0%{!?_without_write_mongodb:0} -# plugin write_riemann disabled, requires a new enough riemann_c_client -%define with_write_riemann 0%{!?_without_write_riemann:0} # plugin xencpu disabled, requires xen-devel from non-default repo %define with_xencpu 0%{!?_without_xencpu:0} # plugin zone disabled, requires Solaris @@ -222,6 +221,7 @@ %define with_turbostat 0 %define with_write_prometheus 0 %define with_write_redis 0 +%define with_write_riemann 0 %endif # Plugins not buildable on RHEL < 7 @@ -233,19 +233,20 @@ %define with_redis 0 %define with_rrdcached 0 %define with_write_redis 0 +%define with_write_riemann 0 %define with_xmms 0 %endif Summary: Statistics collection and monitoring daemon Name: collectd -Version: 5.7.0 -Release: 4%{?dist} +Version: 5.7.1 +Release: 2%{?dist} URL: https://collectd.org Source: https://collectd.org/files/%{name}-%{version}.tar.bz2 License: GPLv2 Group: System Environment/Daemons BuildRoot: %{_tmppath}/%{name}-%{version}-root -BuildRequires: libgcrypt-devel, kernel-headers, libcap-devel, which +BuildRequires: libgcrypt-devel, kernel-headers, libcap-devel, which, xfsprogs-devel Vendor: collectd development team %if 0%{?fedora} || 0%{?rhel} >= 7 @@ -883,7 +884,7 @@ The Write Redis plugin stores values in Redis, a “data structures server”. Summary: riemann plugin for collectd Group: System Environment/Daemons Requires: %{name}%{?_isa} = %{version}-%{release} -BuildRequires: protobuf-c-devel +BuildRequires: riemann-c-client-devel >= 1.6 %description write_riemann The riemann plugin submits values to Riemann, an event stream processor. %endif @@ -2631,6 +2632,13 @@ fi %doc contrib/ %changelog +* Wed Feb 22 2017 Ruben Kerkhof - 5.7.1-2 +- Enable XFS support in df plugin +- Fix bogus date in changelog + +* Sun Jan 01 2017 Marc Fournier - 5.7.1-1 +- New upstream version + * Sat Dec 31 2016 Ruben Kerkhof - 5.7.0-4 - Add new ovs_events plugin diff --git a/contrib/systemd.collectd.service b/contrib/systemd.collectd.service index d0f1bdea..4e2f6ae4 100644 --- a/contrib/systemd.collectd.service +++ b/contrib/systemd.collectd.service @@ -18,8 +18,10 @@ ProtectHome=true # ceph CAP_DAC_OVERRIDE # dns CAP_NET_RAW # exec CAP_SETUID CAP_SETGID +# intel_rdt CAP_SYS_RAWIO # iptables CAP_NET_ADMIN # ping CAP_NET_RAW +# smart CAP_SYS_RAWIO # turbostat CAP_SYS_RAWIO # # Example, if you use the iptables plugin alongside the dns or ping plugin: diff --git a/src/collectd.conf.in b/src/collectd.conf.in index eafe3fbd..1e88bec3 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -114,6 +114,7 @@ #@BUILD_PLUGIN_DF_TRUE@LoadPlugin df #@BUILD_PLUGIN_DISK_TRUE@LoadPlugin disk #@BUILD_PLUGIN_DNS_TRUE@LoadPlugin dns +#@BUILD_PLUGIN_DPDKEVENTS_TRUE@LoadPlugin dpdkevents #@BUILD_PLUGIN_DPDKSTAT_TRUE@LoadPlugin dpdkstat #@BUILD_PLUGIN_DRBD_TRUE@LoadPlugin drbd #@BUILD_PLUGIN_EMAIL_TRUE@LoadPlugin email @@ -526,6 +527,28 @@ # SelectNumericQueryTypes true # +# +# +# Coremask "0x1" +# MemoryChannels "4" +# ProcessType "secondary" +# FilePrefix "rte" +# +# +# SendEventsOnUpdate true +# EnabledPortMask 0xffff +# PortName "interface1" +# PortName "interface2" +# SendNotification false +# +# +# SendEventsOnUpdate true +# LCoreMask "0xf" +# KeepAliveShmName "/dpdk_keepalive_shm_name" +# SendNotification false +# +# + # # # Coremask "0x2" @@ -533,6 +556,7 @@ # ProcessType "secondary" # FilePrefix "rte" # +# SharedMemObj "dpdk_collectd_stats_0" # EnabledPortMask 0xffff # PortName "interface1" # PortName "interface2" @@ -943,6 +967,9 @@ # # UPS "upsname@hostname:port" +# ForceSSL true +# VerifyPeer true +# CAPath "/path/to/folder" # # @@ -1001,6 +1028,7 @@ # Socket "/var/run/openvswitch/db.sock" # Interfaces "br0" "veth0" # SendNotification false +# DispatchValues true # # @@ -1467,6 +1495,7 @@ # InterfaceFormat name # PluginInstanceFormat name # Instances 1 +# ExtraStats "disk pcpu" # # diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 7abd66a1..da8d7933 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2383,6 +2383,128 @@ Enabled by default, collects unknown (and thus presented as numeric only) query =back +=head2 Plugin C + +The I collects events from DPDK such as link status of +network ports and Keep Alive status of DPDK logical cores. +In order to get Keep Alive events following requirements must be met: +- DPDK >= 16.07 +- support for Keep Alive implemented in DPDK application. More details can +be found here: http://dpdk.org/doc/guides/sample_app_ug/keep_alive.html + +B + + + + Coremask "0x1" + MemoryChannels "4" + ProcessType "secondary" + FilePrefix "rte" + + + SendEventsOnUpdate true + EnabledPortMask 0xffff + PortName "interface1" + PortName "interface2" + SendNotification false + + + SendEventsOnUpdate true + LCoreMask "0xf" + KeepAliveShmName "/dpdk_keepalive_shm_name" + SendNotification false + + + +B + + +=head3 The EAL block + +=over 5 + +=item B I + +=item B I + +Number of memory channels per processor socket. + +=item B I + +The type of DPDK process instance. + +=item B I + +The prefix text used for hugepage filenames. The filename will be set to +/var/run/._config where prefix is what is passed in by the user. + +=back + +=head3 The Event block + +The B block defines configuration for specific event. It accepts a +single argument which specifies the name of the event. + +=head4 Link Status event + +=over 5 + +=item B I + +If set to true link status value will be dispatched only when it is +different from previously read value. This is an optional argument - default +value is true. + +=item B I + +A hexidecimal bit mask of the DPDK ports which should be enabled. A mask +of 0x0 means that all ports will be disabled. A bitmask of all F's means +that all ports will be enabled. This is an optional argument - by default +all ports are enabled. + +=item B I + +A string containing an optional name for the enabled DPDK ports. Each PortName +option should contain only one port name; specify as many PortName options as +desired. Default naming convention will be used if PortName is blank. If there +are less PortName options than there are enabled ports, the default naming +convention will be used for the additional ports. + +=item B I + +If set to true, link status notifications are sent, instead of link status +being collected as a statistic. This is an optional argument - default +value is false. + +=back + +=head4 Keep Alive event + +=over 5 + +=item B I + +If set to true keep alive value will be dispatched only when it is +different from previously read value. This is an optional argument - default +value is true. + +=item B I + +An hexadecimal bit mask of the logical cores to monitor keep alive state. + +=item B I + +Shared memory name identifier that is used by secondary process to monitor +the keep alive cores state. + +=item B I + +If set to true, keep alive notifications are sent, instead of keep alive +information being collected as a statistic. This is an optional +argument - default value is false. + +=back + =head2 Plugin C The I collects information about DPDK interfaces using the @@ -2398,6 +2520,7 @@ B FilePrefix "rte" SocketMemory "1024" + SharedMemObj "dpdk_collectd_stats_0" EnabledPortMask 0xffff PortName "interface1" PortName "interface2" @@ -2434,7 +2557,12 @@ sockets in MB. This is an optional value. =back -=over 4 +=over 3 + +=item B I +A string containing the name of the shared memory object that should be used to +share stats from the DPDK secondary process to the collectd dpdkstat plugin. +Defaults to dpdk_collectd_stats if no other value is configured. =item B I @@ -2958,6 +3086,10 @@ allows to monitor instructions per clock (IPC). Monitor events are hardware dependant. Monitoring capabilities are detected on plugin initialization and only supported events are monitored. +B I plugin is using model-specific registers (MSRs), which +require an additional capability to be enabled if collectd is run as a service. +Please refer to I file for more details. + B @@ -5117,6 +5249,35 @@ making it through. Add a UPS to collect data from. The format is identical to the one accepted by L. +=item B B|B + +Stops connections from falling back to unsecured if an SSL connection +cannot be established. Defaults to false if undeclared. + +=item B I|I + +If set to true, requires a CAPath be provided. Will use the CAPath to find +certificates to use as Trusted Certificates to validate a upsd server certificate. +If validation of the upsd server certificate fails, the connection will not be +established. If ForceSSL is undeclared or set to false, setting VerifyPeer to true +will override and set ForceSSL to true. + +=item B I/path/to/certs/folder + +If VerifyPeer is set to true, this is required. Otherwise this is ignored. +The folder pointed at must contain certificate(s) named according to their hash. +Ex: XXXXXXXX.Y where X is the hash value of a cert and Y is 0. If name collisions +occur because two different certs have the same hash value, Y can be incremented +in order to avoid conflict. To create a symbolic link to a certificate the following +command can be used from within the directory where the cert resides: + +C + +Alternatively, the package openssl-perl provides a command C that will +generate links like the one described above for ALL certs in a given folder. +Example usage: +C + =back =head2 Plugin C @@ -5477,6 +5638,7 @@ B Socket "/var/run/openvswitch/db.sock" Interfaces "br0" "veth0" SendNotification false + DispatchValues true The plugin provides the following configuration options: @@ -5516,6 +5678,12 @@ Default: empty (all interfaces on all bridges are monitored) If set to true, OVS link notifications (interface status and OVS DB connection terminate) are sent to collectd. Default value is false. +=item B I + +Dispatch the OVS DB interface link status value with configured plugin interval. +Defaults to true. Please note, if B and B +options are false, no OVS information will be provided by the plugin. + =back B By default, the global interval setting is used within which to @@ -8120,6 +8288,17 @@ How many read instances you want to use for this plugin. The default is one, and the sensible setting is a multiple of the B value. If you are not sure, just use the default setting. +=item B B + +Report additional extra statistics. The default is no extra statistics, preserving +the previous behaviour of the plugin. If unsure, leave the default. If enabled, +allows the plugin to reported more detailed statistics about the behaviour of +Virtual Machines. The argument is a space-separated list of selectors. +Currently supported selectors are: +B report extra statistics like number of flush operations and total +service time for read, write and flush operations. +B report the physical user/system cpu time consumed by the hypervisor, per-vm. + =back =head2 Plugin C diff --git a/src/curl_json.c b/src/curl_json.c index 8e09bd82..4d8677ac 100644 --- a/src/curl_json.c +++ b/src/curl_json.c @@ -600,7 +600,7 @@ static int cj_init_curl(cj_t *db) /* {{{ */ curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, (long)db->timeout); else if (db->interval > 0) curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, - (long)CDTIME_T_TO_MS(db->timeout)); + (long)CDTIME_T_TO_MS(db->interval)); else curl_easy_setopt(db->curl, CURLOPT_TIMEOUT_MS, (long)CDTIME_T_TO_MS(plugin_get_interval())); diff --git a/src/daemon/collectd.c b/src/daemon/collectd.c index f3df795d..6b7c4136 100644 --- a/src/daemon/collectd.c +++ b/src/daemon/collectd.c @@ -521,7 +521,7 @@ int main(int argc, char **argv) { */ if (cf_read(configfile)) { fprintf(stderr, "Error: Reading the config file failed!\n" - "Read the syslog for details.\n"); + "Read the logs for details.\n"); return (1); } diff --git a/src/daemon/common.c b/src/daemon/common.c index 64dbee6f..c45304e8 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -1564,16 +1564,26 @@ void strarray_free(char **array, size_t array_len) /* {{{ */ #if HAVE_CAPABILITY int check_capability(int arg) /* {{{ */ { - cap_value_t cap = (cap_value_t)arg; + cap_value_t cap_value = (cap_value_t)arg; + cap_t cap; + cap_flag_value_t cap_flag_value; - if (!CAP_IS_SUPPORTED(cap)) + if (!CAP_IS_SUPPORTED(cap_value)) return (-1); - int have_cap = cap_get_bound(cap); - if (have_cap != 1) + if (!(cap = cap_get_proc())) { + ERROR("check_capability: cap_get_proc failed."); return (-1); + } - return (0); + if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) { + ERROR("check_capability: cap_get_flag failed."); + cap_free(cap); + return (-1); + } + cap_free(cap); + + return (cap_flag_value != CAP_SET); } /* }}} int check_capability */ #else int check_capability(__attribute__((unused)) int arg) /* {{{ */ diff --git a/src/daemon/common.h b/src/daemon/common.h index a1a25289..8947c575 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -385,7 +385,7 @@ void strarray_free(char **array, size_t array_len); * argument. Returns zero if it does, less than zero if it doesn't or on error. * See capabilities(7) for the list of possible capabilities. * */ -int check_capability(int capability); +int check_capability(int arg); #endif /* HAVE_SYS_CAPABILITY_H */ #endif /* COMMON_H */ diff --git a/src/daemon/plugin.c b/src/daemon/plugin.c index c8fc15a1..b37e9b32 100644 --- a/src/daemon/plugin.c +++ b/src/daemon/plugin.c @@ -153,14 +153,13 @@ static const char *plugin_get_dir(void) { return (plugindir); } -static void plugin_update_internal_statistics(void) { /* {{{ */ - +static int plugin_update_internal_statistics(void) { /* {{{ */ gauge_t copy_write_queue_length = (gauge_t)write_queue_length; /* Initialize `vl' */ value_list_t vl = VALUE_LIST_INIT; - sstrncpy(vl.host, hostname_g, sizeof(vl.host)); sstrncpy(vl.plugin, "collectd", sizeof(vl.plugin)); + vl.interval = plugin_get_interval(); /* Write queue */ sstrncpy(vl.plugin_instance, "write_queue", sizeof(vl.plugin_instance)); @@ -189,8 +188,8 @@ static void plugin_update_internal_statistics(void) { /* {{{ */ vl.type_instance[0] = 0; plugin_dispatch_values(&vl); - return; -} /* }}} void plugin_update_internal_statistics */ + return 0; +} /* }}} int plugin_update_internal_statistics */ static void destroy_callback(callback_func_t *cf) /* {{{ */ { @@ -1558,8 +1557,10 @@ int plugin_init_all(void) { /* Init the value cache */ uc_init(); - if (IS_TRUE(global_option_get("CollectInternalStats"))) + if (IS_TRUE(global_option_get("CollectInternalStats"))) { record_statistics = 1; + plugin_register_read("collectd", plugin_update_internal_statistics); + } chain_name = global_option_get("PreCacheChain"); pre_cache_chain = fc_chain_get_by_name(chain_name); @@ -1647,9 +1648,6 @@ int plugin_init_all(void) { /* TODO: Rename this function. */ void plugin_read_all(void) { - if (record_statistics) { - plugin_update_internal_statistics(); - } uc_check_timeout(); return; diff --git a/src/dpdkevents.c b/src/dpdkevents.c new file mode 100644 index 00000000..6be6bc04 --- /dev/null +++ b/src/dpdkevents.c @@ -0,0 +1,584 @@ +/* + * collectd - src/dpdkevents.c + * MIT License + * + * Copyright(c) 2017 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 + * Harry van Haaren + * Serhiy Pshyk + * Kim-Marie Jones + * Krzysztof Matczak + */ + +#include "collectd.h" + +#include "common.h" +#include "plugin.h" + +#include "semaphore.h" +#include "sys/mman.h" +#include "utils_dpdk.h" +#include "utils_time.h" + +#include +#include +#include +#include + +#define DPDK_EVENTS_PLUGIN "dpdkevents" +#define DPDK_EVENTS_NAME "dpdk_collectd_events" +#define ETH_LINK_NA 0xFF + +#define INT64_BIT_SIZE 64 +#define KEEPALIVE_PLUGIN_INSTANCE "keepalive" +#define RTE_KEEPALIVE_SHM_NAME "/dpdk_keepalive_shm_name" + +typedef struct dpdk_keepalive_shm_s { + sem_t core_died; + enum rte_keepalive_state core_state[RTE_KEEPALIVE_MAXCORES]; + uint64_t core_last_seen_times[RTE_KEEPALIVE_MAXCORES]; +} dpdk_keepalive_shm_t; + +typedef struct dpdk_ka_monitor_s { + cdtime_t read_time; + int lcore_state; +} dpdk_ka_monitor_t; + +typedef struct dpdk_link_status_config_s { + int enabled; + int send_updated; + uint32_t enabled_port_mask; + char port_name[RTE_MAX_ETHPORTS][DATA_MAX_NAME_LEN]; + int notify; +} dpdk_link_status_config_t; + +typedef struct dpdk_keep_alive_config_s { + int enabled; + int send_updated; + uint128_t lcore_mask; + dpdk_keepalive_shm_t *shm; + char shm_name[DATA_MAX_NAME_LEN]; + int notify; +} dpdk_keep_alive_config_t; + +typedef struct dpdk_events_config_s { + cdtime_t interval; + dpdk_link_status_config_t link_status; + dpdk_keep_alive_config_t keep_alive; +} dpdk_events_config_t; + +typedef struct dpdk_link_info_s { + cdtime_t read_time; + int status_updated; + int link_status; +} dpdk_link_info_t; + +typedef struct dpdk_events_ctx_s { + dpdk_events_config_t config; + uint32_t nb_ports; + dpdk_link_info_t link_info[RTE_MAX_ETHPORTS]; + dpdk_ka_monitor_t core_info[RTE_KEEPALIVE_MAXCORES]; +} dpdk_events_ctx_t; + +#define DPDK_EVENTS_CTX_GET(a) ((dpdk_events_ctx_t *)dpdk_helper_priv_get(a)) + +#define DPDK_EVENTS_TRACE() \ + DEBUG("%s:%s:%d pid=%u", DPDK_EVENTS_PLUGIN, __FUNCTION__, __LINE__, getpid()) + +static dpdk_helper_ctx_t *g_hc; + +static int dpdk_event_keep_alive_shm_create(void) { + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + char *shm_name; + + if (strlen(ec->config.keep_alive.shm_name)) { + shm_name = ec->config.keep_alive.shm_name; + } else { + shm_name = RTE_KEEPALIVE_SHM_NAME; + WARNING(DPDK_EVENTS_PLUGIN ": Keep alive shared memory identifier is not " + "specified, using default one: %s", + shm_name); + } + + char errbuf[ERR_BUF_SIZE]; + int fd = shm_open(shm_name, O_RDWR, 0); + if (fd < 0) { + ERROR(DPDK_EVENTS_PLUGIN ": Failed to open %s as SHM:%s. Is DPDK KA " + "primary application running?", + shm_name, sstrerror(errno, errbuf, sizeof(errbuf))); + return errno; + } else { + ec->config.keep_alive.shm = + (dpdk_keepalive_shm_t *)mmap(0, sizeof(*(ec->config.keep_alive.shm)), + PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + close(fd); + if (ec->config.keep_alive.shm == MAP_FAILED) { + ERROR(DPDK_EVENTS_PLUGIN ": Failed to mmap KA SHM:%s", + sstrerror(errno, errbuf, sizeof(errbuf))); + return errno; + } + } + + return 0; +} + +static void dpdk_events_default_config(void) { + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + + ec->config.interval = plugin_get_interval(); + + /* Link Status */ + ec->config.link_status.enabled = 0; + ec->config.link_status.enabled_port_mask = ~0; + ec->config.link_status.send_updated = 1; + ec->config.link_status.notify = 0; + + for (int i = 0; i < RTE_MAX_ETHPORTS; i++) { + ec->config.link_status.port_name[i][0] = 0; + } + + /* Keep Alive */ + ec->config.keep_alive.enabled = 0; + ec->config.keep_alive.send_updated = 1; + ec->config.keep_alive.notify = 0; + memset(&ec->config.keep_alive.lcore_mask, 0, + sizeof(ec->config.keep_alive.lcore_mask)); + memset(&ec->config.keep_alive.shm_name, 0, + sizeof(ec->config.keep_alive.shm_name)); +} + +static int dpdk_events_preinit(void) { + DPDK_EVENTS_TRACE(); + + if (g_hc != NULL) { + /* already initialized if config callback was called before init callback */ + DEBUG("dpdk_events_preinit: helper already initialized."); + return 0; + } + + int ret = + dpdk_helper_init(DPDK_EVENTS_NAME, sizeof(dpdk_events_ctx_t), &g_hc); + if (ret != 0) { + ERROR(DPDK_EVENTS_PLUGIN ": failed to initialize %s helper(error: %s)", + DPDK_EVENTS_NAME, strerror(ret)); + return ret; + } + + dpdk_events_default_config(); + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + for (int i = 0; i < RTE_MAX_ETHPORTS; i++) { + ec->link_info[i].link_status = ETH_LINK_NA; + } + + for (int i = 0; i < RTE_KEEPALIVE_MAXCORES; i++) { + ec->core_info[i].lcore_state = ETH_LINK_NA; + } + + return ret; +} + +static int dpdk_events_link_status_config(dpdk_events_ctx_t *ec, + oconfig_item_t *ci) { + ec->config.link_status.enabled = 1; + + DEBUG(DPDK_EVENTS_PLUGIN ": Subscribed for Link Status Events."); + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *child = ci->children + i; + + if (strcasecmp("EnabledPortMask", child->key) == 0) { + ec->config.link_status.enabled_port_mask = + (uint32_t)child->values[0].value.number; + DEBUG(DPDK_EVENTS_PLUGIN ": LinkStatus:Enabled Port Mask 0x%X", + ec->config.link_status.enabled_port_mask); + } else if (strcasecmp("SendEventsOnUpdate", child->key) == 0) { + ec->config.link_status.send_updated = child->values[0].value.boolean; + DEBUG(DPDK_EVENTS_PLUGIN ": LinkStatus:SendEventsOnUpdate %d", + (int)child->values[0].value.boolean); + } else if (strcasecmp("SendNotification", child->key) == 0) { + ec->config.link_status.notify = child->values[0].value.boolean; + DEBUG(DPDK_EVENTS_PLUGIN ": LinkStatus:SendNotification %d", + (int)child->values[0].value.boolean); + } + } + + int port_num = 0; + + /* parse port names after EnabledPortMask was parsed */ + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *child = ci->children + i; + if (strcasecmp("PortName", child->key) == 0) { + while (!(ec->config.link_status.enabled_port_mask & (1 << port_num))) + port_num++; + ssnprintf(ec->config.link_status.port_name[port_num], DATA_MAX_NAME_LEN, + "%s", child->values[0].value.string); + DEBUG(DPDK_EVENTS_PLUGIN ": LinkStatus:Port %d Name: %s", port_num, + ec->config.link_status.port_name[port_num]); + port_num++; + } + } + + return 0; +} + +static int dpdk_events_keep_alive_config(dpdk_events_ctx_t *ec, + oconfig_item_t *ci) { + ec->config.keep_alive.enabled = 1; + DEBUG(DPDK_EVENTS_PLUGIN ": Subscribed for Keep Alive Events."); + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *child = ci->children + i; + + if (strcasecmp("SendEventsOnUpdate", child->key) == 0) { + ec->config.keep_alive.send_updated = child->values[0].value.boolean; + DEBUG(DPDK_EVENTS_PLUGIN ": KeepAlive:SendEventsOnUpdate %d", + (int)child->values[0].value.boolean); + } else if (strcasecmp("LCoreMask", child->key) == 0) { + char lcore_mask[DATA_MAX_NAME_LEN]; + ssnprintf(lcore_mask, sizeof(lcore_mask), "%s", + child->values[0].value.string); + ec->config.keep_alive.lcore_mask = + str_to_uint128(lcore_mask, strlen(lcore_mask)); + DEBUG(DPDK_EVENTS_PLUGIN ": KeepAlive:LCoreMask 0x%" PRIX64 "%" PRIX64 "", + ec->config.keep_alive.lcore_mask.high, + ec->config.keep_alive.lcore_mask.low); + } else if (strcasecmp("KeepAliveShmName", child->key) == 0) { + ssnprintf(ec->config.keep_alive.shm_name, + sizeof(ec->config.keep_alive.shm_name), "%s", + child->values[0].value.string); + DEBUG(DPDK_EVENTS_PLUGIN ": KeepAlive:KeepAliveShmName %s", + ec->config.keep_alive.shm_name); + } else if (strcasecmp("SendNotification", child->key) == 0) { + ec->config.keep_alive.notify = child->values[0].value.boolean; + DEBUG(DPDK_EVENTS_PLUGIN ": KeepAlive:SendNotification %d", + (int)child->values[0].value.boolean); + } + } + + return 0; +} + +static int dpdk_events_config(oconfig_item_t *ci) { + DPDK_EVENTS_TRACE(); + + int ret = dpdk_events_preinit(); + if (ret) + return ret; + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + + for (int i = 0; i < ci->children_num; i++) { + oconfig_item_t *child = ci->children + i; + if (strcasecmp("EAL", child->key) == 0) { + dpdk_helper_eal_config_parse(g_hc, child); + } else if (strcasecmp("Event", child->key) == 0) { + if (strcasecmp(child->values[0].value.string, "link_status") == 0) { + dpdk_events_link_status_config(ec, child); + } else if (strcasecmp(child->values[0].value.string, "keep_alive") == 0) { + dpdk_events_keep_alive_config(ec, child); + } else { + ERROR(DPDK_EVENTS_PLUGIN ": The selected event \"%s\" is unknown.", + child->values[0].value.string); + } + } + } + + if (!ec->config.keep_alive.enabled && !ec->config.link_status.enabled) { + ERROR(DPDK_EVENTS_PLUGIN ": At least one type of events should be " + "configured for collecting. Plugin misconfigured"); + return -1; + } + + return ret; +} + +static int dpdk_helper_link_status_get(dpdk_helper_ctx_t *phc) { + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(phc); + + /* get Link Status values from DPDK */ + uint8_t nb_ports = rte_eth_dev_count(); + if (nb_ports == 0) { + DPDK_CHILD_LOG("dpdkevent-helper: No DPDK ports available. " + "Check bound devices to DPDK driver.\n"); + return -ENODEV; + } + ec->nb_ports = nb_ports > RTE_MAX_ETHPORTS ? RTE_MAX_ETHPORTS : nb_ports; + + for (int i = 0; i < ec->nb_ports; i++) { + if (ec->config.link_status.enabled_port_mask & (1 << i)) { + struct rte_eth_link link; + ec->link_info[i].read_time = cdtime(); + rte_eth_link_get_nowait(i, &link); + if ((link.link_status == ETH_LINK_NA) || + (link.link_status != ec->link_info[i].link_status)) { + ec->link_info[i].link_status = link.link_status; + ec->link_info[i].status_updated = 1; + DPDK_CHILD_LOG(" === PORT %d Link Status: %s\n", i, + link.link_status ? "UP" : "DOWN"); + } + } + } + + return 0; +} + +/* this function is called from helper context */ +int dpdk_helper_command_handler(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd) { + if (phc == NULL) { + DPDK_CHILD_LOG(DPDK_EVENTS_PLUGIN ": Invalid argument(phc)\n"); + return -EINVAL; + } + + if (cmd != DPDK_CMD_GET_EVENTS) { + DPDK_CHILD_LOG(DPDK_EVENTS_PLUGIN ": Unknown command (cmd=%d)\n", cmd); + return -EINVAL; + } + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(phc); + int ret = 0; + if (ec->config.link_status.enabled) + ret = dpdk_helper_link_status_get(phc); + + return ret; +} + +static void dpdk_events_notification_dispatch(int severity, + const char *plugin_instance, + cdtime_t time, const char *msg) { + notification_t n = { + .severity = severity, .time = time, .plugin = DPDK_EVENTS_PLUGIN}; + sstrncpy(n.host, hostname_g, sizeof(n.host)); + sstrncpy(n.plugin_instance, plugin_instance, sizeof(n.plugin_instance)); + sstrncpy(n.message, msg, sizeof(n.message)); + plugin_dispatch_notification(&n); +} + +static void dpdk_events_gauge_submit(const char *plugin_instance, + const char *type_instance, gauge_t value, + cdtime_t time) { + value_list_t vl = {.values = &(value_t){.gauge = value}, + .values_len = 1, + .time = time, + .plugin = DPDK_EVENTS_PLUGIN, + .type = "gauge", + .meta = NULL}; + sstrncpy(vl.host, hostname_g, sizeof(vl.host)); + sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance)); + sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance)); + plugin_dispatch_values(&vl); +} + +static int dpdk_events_link_status_dispatch(dpdk_helper_ctx_t *phc) { + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(phc); + DEBUG(DPDK_EVENTS_PLUGIN ": %s:%d ports=%u", __FUNCTION__, __LINE__, + ec->nb_ports); + + /* dispatch Link Status values to collectd */ + for (int i = 0; i < ec->nb_ports; i++) { + if (ec->config.link_status.enabled_port_mask & (1 << i)) { + if (!ec->config.link_status.send_updated || + ec->link_info[i].status_updated) { + + DEBUG(DPDK_EVENTS_PLUGIN ": Dispatch PORT %d Link Status: %s", i, + ec->link_info[i].link_status ? "UP" : "DOWN"); + + char dev_name[DATA_MAX_NAME_LEN]; + if (ec->config.link_status.port_name[i][0] != 0) { + ssnprintf(dev_name, sizeof(dev_name), "%s", + ec->config.link_status.port_name[i]); + } else { + ssnprintf(dev_name, sizeof(dev_name), "port.%d", i); + } + + if (ec->config.link_status.notify) { + int sev = ec->link_info[i].link_status ? NOTIF_OKAY : NOTIF_WARNING; + char msg[DATA_MAX_NAME_LEN]; + ssnprintf(msg, sizeof(msg), "Link Status: %s", + ec->link_info[i].link_status ? "UP" : "DOWN"); + dpdk_events_notification_dispatch(sev, dev_name, + ec->link_info[i].read_time, msg); + } else { + dpdk_events_gauge_submit(dev_name, "link_status", + (gauge_t)ec->link_info[i].link_status, + ec->link_info[i].read_time); + } + ec->link_info[i].status_updated = 0; + } + } + } + + return 0; +} + +static void dpdk_events_keep_alive_dispatch(dpdk_helper_ctx_t *phc) { + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(phc); + + /* dispatch Keep Alive values to collectd */ + for (int i = 0; i < RTE_KEEPALIVE_MAXCORES; i++) { + if (i < INT64_BIT_SIZE) { + if (!(ec->config.keep_alive.lcore_mask.low & ((uint64_t)1 << i))) + continue; + } else if (i >= INT64_BIT_SIZE && i < INT64_BIT_SIZE * 2) { + if (!(ec->config.keep_alive.lcore_mask.high & + ((uint64_t)1 << (i - INT64_BIT_SIZE)))) + continue; + } else { + WARNING(DPDK_EVENTS_PLUGIN + ": %s:%d Core id %u is out of 0 to %u range, skipping", + __FUNCTION__, __LINE__, i, INT64_BIT_SIZE * 2); + continue; + } + + char core_name[DATA_MAX_NAME_LEN]; + ssnprintf(core_name, sizeof(core_name), "lcore%u", i); + + if (!ec->config.keep_alive.send_updated || + (ec->core_info[i].lcore_state != + ec->config.keep_alive.shm->core_state[i])) { + ec->core_info[i].lcore_state = ec->config.keep_alive.shm->core_state[i]; + ec->core_info[i].read_time = cdtime(); + + if (ec->config.keep_alive.notify) { + char msg[DATA_MAX_NAME_LEN]; + int sev; + + switch (ec->config.keep_alive.shm->core_state[i]) { + case RTE_KA_STATE_ALIVE: + sev = NOTIF_OKAY; + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: ALIVE", i); + break; + case RTE_KA_STATE_MISSING: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: MISSING", i); + sev = NOTIF_WARNING; + break; + case RTE_KA_STATE_DEAD: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DEAD", i); + sev = NOTIF_FAILURE; + break; + case RTE_KA_STATE_UNUSED: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNUSED", i); + sev = NOTIF_OKAY; + break; + case RTE_KA_STATE_GONE: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: GONE", i); + sev = NOTIF_FAILURE; + break; + case RTE_KA_STATE_DOZING: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: DOZING", i); + sev = NOTIF_OKAY; + break; + case RTE_KA_STATE_SLEEP: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: SLEEP", i); + sev = NOTIF_OKAY; + break; + default: + ssnprintf(msg, sizeof(msg), "lcore %u Keep Alive Status: UNKNOWN", i); + sev = NOTIF_FAILURE; + } + + dpdk_events_notification_dispatch(sev, KEEPALIVE_PLUGIN_INSTANCE, + ec->core_info[i].read_time, msg); + } else { + dpdk_events_gauge_submit(KEEPALIVE_PLUGIN_INSTANCE, core_name, + ec->config.keep_alive.shm->core_state[i], + ec->core_info[i].read_time); + } + } + } +} + +static int dpdk_events_read(user_data_t *ud) { + DPDK_EVENTS_TRACE(); + + if (g_hc == NULL) { + ERROR(DPDK_EVENTS_PLUGIN ": plugin not initialized."); + return -1; + } + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + + if (ec->config.link_status.enabled) { + int cmd_res = 0; + int ret = dpdk_helper_command(g_hc, DPDK_CMD_GET_EVENTS, &cmd_res, + ec->config.interval); + if (cmd_res == 0 && ret == 0) { + dpdk_events_link_status_dispatch(g_hc); + } + } + + if (ec->config.keep_alive.enabled) { + dpdk_events_keep_alive_dispatch(g_hc); + } + + return 0; +} + +static int dpdk_events_init(void) { + DPDK_EVENTS_TRACE(); + + int ret = dpdk_events_preinit(); + if (ret) + return ret; + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + + if (ec->config.keep_alive.enabled) { + ret = dpdk_event_keep_alive_shm_create(); + if (ret) { + ERROR(DPDK_EVENTS_PLUGIN ": %s : error %d in ka_shm_create()", + __FUNCTION__, ret); + return ret; + } + } + return 0; +} + +static int dpdk_events_shutdown(void) { + DPDK_EVENTS_TRACE(); + int ret; + + dpdk_events_ctx_t *ec = DPDK_EVENTS_CTX_GET(g_hc); + if (ec->config.keep_alive.enabled) { + ret = munmap(ec->config.keep_alive.shm, sizeof(dpdk_keepalive_shm_t)); + if (ret) { + ERROR(DPDK_EVENTS_PLUGIN ": munmap KA monitor returned %d", ret); + return ret; + } + } + + ret = dpdk_helper_shutdown(g_hc); + g_hc = NULL; + if (ret) + ERROR(DPDK_EVENTS_PLUGIN ": failed to cleanup %s helper", DPDK_EVENTS_NAME); + + return ret; +} + +void module_register(void) { + plugin_register_init(DPDK_EVENTS_PLUGIN, dpdk_events_init); + plugin_register_complex_config(DPDK_EVENTS_PLUGIN, dpdk_events_config); + plugin_register_complex_read(NULL, DPDK_EVENTS_PLUGIN, dpdk_events_read, 0, + NULL); + plugin_register_shutdown(DPDK_EVENTS_PLUGIN, dpdk_events_shutdown); +} diff --git a/src/dpdkstat.c b/src/dpdkstat.c index e3350725..6b057f21 100644 --- a/src/dpdkstat.c +++ b/src/dpdkstat.c @@ -94,12 +94,12 @@ typedef struct dpdk_stats_ctx_s dpdk_stats_ctx_t; #define DPDK_STATS_CTX_GET(a) ((dpdk_stats_ctx_t *)dpdk_helper_priv_get(a)) dpdk_helper_ctx_t *g_hc = NULL; - +static char g_shm_name[DATA_MAX_NAME_LEN] = DPDK_STATS_NAME; +static int dpdk_stats_reinit_helper(); static void dpdk_stats_default_config(void) { dpdk_stats_ctx_t *ec = DPDK_STATS_CTX_GET(g_hc); ec->config.interval = plugin_get_interval(); - for (int i = 0; i < RTE_MAX_ETHPORTS; i++) { ec->config.port_name[i][0] = 0; } @@ -114,16 +114,15 @@ static int dpdk_stats_preinit(void) { return 0; } - int ret = dpdk_helper_init(DPDK_STATS_NAME, sizeof(dpdk_stats_ctx_t), &g_hc); + int ret = dpdk_helper_init(g_shm_name, sizeof(dpdk_stats_ctx_t), &g_hc); if (ret != 0) { char errbuf[ERR_BUF_SIZE]; ERROR("%s: failed to initialize %s helper(error: %s)", DPDK_STATS_PLUGIN, - DPDK_STATS_NAME, sstrerror(errno, errbuf, sizeof(errbuf))); + g_shm_name, sstrerror(errno, errbuf, sizeof(errbuf))); return ret; } dpdk_stats_default_config(); - return ret; } @@ -144,6 +143,10 @@ static int dpdk_stats_config(oconfig_item_t *ci) { ctx->config.enabled_port_mask = child->values[0].value.number; DEBUG("%s: Enabled Port Mask 0x%X", DPDK_STATS_PLUGIN, ctx->config.enabled_port_mask); + } else if (strcasecmp("SharedMemObj", child->key) == 0) { + cf_util_get_string_buffer(child, g_shm_name, sizeof(g_shm_name)); + DEBUG("%s: Shared memory object %s", DPDK_STATS_PLUGIN, g_shm_name); + dpdk_stats_reinit_helper(); } else if (strcasecmp("EAL", child->key) == 0) { ret = dpdk_helper_eal_config_parse(g_hc, child); if (ret) @@ -175,73 +178,56 @@ static int dpdk_stats_config(oconfig_item_t *ci) { } static int dpdk_helper_stats_get(dpdk_helper_ctx_t *phc) { - dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); - - /* get stats from DPDK */ - - uint8_t ports_count = rte_eth_dev_count(); - if (ports_count == 0) { - DPDK_CHILD_LOG("%s: No DPDK ports available. " - "Check bound devices to DPDK driver.\n", - DPDK_STATS_PLUGIN); - return -ENODEV; - } - - if (ports_count > RTE_MAX_ETHPORTS) - ports_count = RTE_MAX_ETHPORTS; - - ctx->ports_count = ports_count; - int len = 0; int ret = 0; int stats = 0; + dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); - for (uint8_t i = 0; i < ports_count; i++) { + /* get stats from DPDK */ + for (uint8_t i = 0; i < ctx->ports_count; i++) { if (!(ctx->config.enabled_port_mask & (1 << i))) continue; + ctx->port_read_time[i] = cdtime(); + /* Store available stats array length for port */ len = ctx->port_stats_count[i]; + ret = rte_eth_xstats_get(i, &ctx->xstats[stats], len); - if (ret < 0 || ret != len) { - DPDK_CHILD_LOG("%s: Error reading stats (port=%d; len=%d)\n", - DPDK_STATS_PLUGIN, i, len); + if (ret < 0 || ret > len) { + DPDK_CHILD_LOG(DPDK_STATS_PLUGIN + ": Error reading stats (port=%d; len=%d, ret=%d)\n", + i, len, ret); + ctx->port_stats_count[i] = 0; return -1; } #if RTE_VERSION >= RTE_VERSION_16_07 ret = rte_eth_xstats_get_names(i, &ctx->xnames[stats], len); - if (ret < 0 || ret != len) { - DPDK_CHILD_LOG("%s: Error reading stat names (port=%d; len=%d)\n", - DPDK_STATS_PLUGIN, i, len); + if (ret < 0 || ret > len) { + DPDK_CHILD_LOG(DPDK_STATS_PLUGIN + ": Error reading stat names (port=%d; len=%d ret=%d)\n", + i, len, ret); + ctx->port_stats_count[i] = 0; return -1; } #endif - stats += len; + ctx->port_stats_count[i] = ret; + stats += ctx->port_stats_count[i]; } - assert(stats == ctx->stats_count); - + assert(stats <= ctx->stats_count); return 0; } static int dpdk_helper_stats_count_get(dpdk_helper_ctx_t *phc) { - dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); - - uint8_t ports = rte_eth_dev_count(); - if (ports == 0) { - DPDK_CHILD_LOG("%s: No DPDK ports available. " - "Check bound devices to DPDK driver.\n", - DPDK_STATS_PLUGIN); + uint8_t ports = dpdk_helper_eth_dev_count(); + if (ports == 0) return -ENODEV; - } - - if (ports > RTE_MAX_ETHPORTS) - ports = RTE_MAX_ETHPORTS; + dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); ctx->ports_count = ports; int len = 0; int stats_count = 0; - for (int i = 0; i < ports; i++) { if (!(ctx->config.enabled_port_mask & (1 << i))) continue; @@ -264,9 +250,12 @@ static int dpdk_helper_stats_count_get(dpdk_helper_ctx_t *phc) { return stats_count; } +static int dpdk_stats_get_size(dpdk_helper_ctx_t *phc) { + return (dpdk_helper_data_size_get(phc) - sizeof(dpdk_stats_ctx_t)); +} + int dpdk_helper_command_handler(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd) { /* this function is called from helper context */ - int ret = 0; if (phc == NULL) { DPDK_CHILD_LOG("%s: Invalid argument(phc)\n", DPDK_STATS_PLUGIN); @@ -278,34 +267,23 @@ int dpdk_helper_command_handler(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd) { return -EINVAL; } - dpdk_stats_ctx_t *ctx = DPDK_STATS_CTX_GET(phc); - - if (ctx->stats_count == 0) { - - int stats_count = dpdk_helper_stats_count_get(phc); + int stats_count = dpdk_helper_stats_count_get(phc); + if (stats_count < 0) { + return stats_count; + } - if (stats_count < 0) { - return stats_count; - } + DPDK_STATS_CTX_GET(phc)->stats_count = stats_count; + int stats_size = stats_count * DPDK_STATS_CTX_GET_XSTAT_SIZE; - int stats_size = stats_count * DPDK_STATS_CTX_GET_XSTAT_SIZE; - ctx->stats_count = stats_count; - - if ((dpdk_helper_data_size_get(phc) - sizeof(dpdk_stats_ctx_t)) < - stats_size) { - DPDK_CHILD_LOG( - "%s:%s:%d not enough space for stats (available=%d, " - "needed=%d)\n", - DPDK_STATS_PLUGIN, __FUNCTION__, __LINE__, - (int)(dpdk_helper_data_size_get(phc) - sizeof(dpdk_stats_ctx_t)), - stats_size); - return -ENOBUFS; - } + if (dpdk_stats_get_size(phc) < stats_size) { + DPDK_CHILD_LOG( + DPDK_STATS_PLUGIN + ":%s:%d not enough space for stats (available=%d, needed=%d)\n", + __FUNCTION__, __LINE__, (int)dpdk_stats_get_size(phc), stats_size); + return -ENOBUFS; } - ret = dpdk_helper_stats_get(phc); - - return ret; + return dpdk_helper_stats_get(phc); } static void dpdk_stats_resolve_cnt_type(char *cnt_type, size_t cnt_type_len, @@ -314,17 +292,17 @@ static void dpdk_stats_resolve_cnt_type(char *cnt_type, size_t cnt_type_len, type_end = strrchr(cnt_name, '_'); if ((type_end != NULL) && (strncmp(cnt_name, "rx_", strlen("rx_")) == 0)) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "bytes") != NULL) { + sstrncpy(cnt_type, "if_rx_octets", cnt_type_len); + } else if (strstr(type_end, "error") != NULL) { sstrncpy(cnt_type, "if_rx_errors", cnt_type_len); - } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + } else if (strstr(type_end, "dropped") != NULL) { sstrncpy(cnt_type, "if_rx_dropped", cnt_type_len); - } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { - sstrncpy(cnt_type, "if_rx_octets", cnt_type_len); - } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + } else if (strstr(type_end, "packets") != NULL) { sstrncpy(cnt_type, "if_rx_packets", cnt_type_len); - } else if (strncmp(type_end, "_placement", strlen("_placement")) == 0) { + } else if (strstr(type_end, "_placement") != NULL) { sstrncpy(cnt_type, "if_rx_errors", cnt_type_len); - } else if (strncmp(type_end, "_buff", strlen("_buff")) == 0) { + } else if (strstr(type_end, "_buff") != NULL) { sstrncpy(cnt_type, "if_rx_errors", cnt_type_len); } else { /* Does not fit obvious type: use a more generic one */ @@ -333,13 +311,13 @@ static void dpdk_stats_resolve_cnt_type(char *cnt_type, size_t cnt_type_len, } else if ((type_end != NULL) && (strncmp(cnt_name, "tx_", strlen("tx_"))) == 0) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "bytes") != NULL) { + sstrncpy(cnt_type, "if_tx_octets", cnt_type_len); + } else if (strstr(type_end, "error") != NULL) { sstrncpy(cnt_type, "if_tx_errors", cnt_type_len); - } else if (strncmp(type_end, "_dropped", strlen("_dropped")) == 0) { + } else if (strstr(type_end, "dropped") != NULL) { sstrncpy(cnt_type, "if_tx_dropped", cnt_type_len); - } else if (strncmp(type_end, "_bytes", strlen("_bytes")) == 0) { - sstrncpy(cnt_type, "if_tx_octets", cnt_type_len); - } else if (strncmp(type_end, "_packets", strlen("_packets")) == 0) { + } else if (strstr(type_end, "packets") != NULL) { sstrncpy(cnt_type, "if_tx_packets", cnt_type_len); } else { /* Does not fit obvious type: use a more generic one */ @@ -348,16 +326,14 @@ static void dpdk_stats_resolve_cnt_type(char *cnt_type, size_t cnt_type_len, } else if ((type_end != NULL) && (strncmp(cnt_name, "flow_", strlen("flow_"))) == 0) { - if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { + if (strstr(type_end, "_filters") != NULL) { sstrncpy(cnt_type, "operations", cnt_type_len); - } else if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + } else if (strstr(type_end, "error") != NULL) sstrncpy(cnt_type, "errors", cnt_type_len); - } else if (strncmp(type_end, "_filters", strlen("_filters")) == 0) { - sstrncpy(cnt_type, "filter_result", cnt_type_len); - } + } else if ((type_end != NULL) && (strncmp(cnt_name, "mac_", strlen("mac_"))) == 0) { - if (strncmp(type_end, "_errors", strlen("_errors")) == 0) { + if (strstr(type_end, "error") != NULL) { sstrncpy(cnt_type, "errors", cnt_type_len); } } else { @@ -446,11 +422,11 @@ static int dpdk_stats_reinit_helper() { g_hc = NULL; int ret; - ret = dpdk_helper_init(DPDK_STATS_NAME, data_size, &g_hc); + ret = dpdk_helper_init(g_shm_name, data_size, &g_hc); if (ret != 0) { char errbuf[ERR_BUF_SIZE]; ERROR("%s: failed to initialize %s helper(error: %s)", DPDK_STATS_PLUGIN, - DPDK_STATS_NAME, sstrerror(errno, errbuf, sizeof(errbuf))); + g_shm_name, sstrerror(errno, errbuf, sizeof(errbuf))); return ret; } @@ -494,7 +470,6 @@ static int dpdk_stats_read(user_data_t *ud) { static int dpdk_stats_init(void) { DPDK_STATS_TRACE(); - int ret = 0; ret = dpdk_stats_preinit(); @@ -513,8 +488,7 @@ static int dpdk_stats_shutdown(void) { ret = dpdk_helper_shutdown(g_hc); g_hc = NULL; if (ret != 0) { - ERROR("%s: failed to cleanup %s helper", DPDK_STATS_PLUGIN, - DPDK_STATS_NAME); + ERROR("%s: failed to cleanup %s helper", DPDK_STATS_PLUGIN, g_shm_name); return ret; } diff --git a/src/intel_rdt.c b/src/intel_rdt.c index 6beac7b4..e2e2e394 100644 --- a/src/intel_rdt.c +++ b/src/intel_rdt.c @@ -36,6 +36,11 @@ #define RDT_MAX_SOCKET_CORES 64 #define RDT_MAX_CORES (RDT_MAX_SOCKET_CORES * RDT_MAX_SOCKETS) +typedef enum { + UNKNOWN = 0, + CONFIGURATION_ERROR, +} rdt_config_status; + struct rdt_core_group_s { char *desc; size_t num_cores; @@ -56,6 +61,8 @@ typedef struct rdt_ctx_s rdt_ctx_t; static rdt_ctx_t *g_rdt = NULL; +static rdt_config_status g_state = UNKNOWN; + static int isdup(const uint64_t *nums, size_t size, uint64_t val) { for (size_t i = 0; i < size; i++) if (nums[i] == val) @@ -527,8 +534,14 @@ static int rdt_config(oconfig_item_t *ci) { int ret = 0; ret = rdt_preinit(); - if (ret != 0) - return ret; + if (ret != 0) { + g_state = CONFIGURATION_ERROR; + /* if we return -1 at this point collectd + reports a failure in configuration and + aborts + */ + goto exit; + } for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -536,8 +549,14 @@ static int rdt_config(oconfig_item_t *ci) { if (strcasecmp("Cores", child->key) == 0) { ret = rdt_config_cgroups(child); - if (ret != 0) - return ret; + if (ret != 0) { + g_state = CONFIGURATION_ERROR; + /* if we return -1 at this point collectd + reports a failure in configuration and + aborts + */ + goto exit; + } #if COLLECT_DEBUG rdt_dump_cgroups(); @@ -548,6 +567,7 @@ static int rdt_config(oconfig_item_t *ci) { } } +exit: return (0); } @@ -630,6 +650,9 @@ static int rdt_read(__attribute__((unused)) user_data_t *ud) { static int rdt_init(void) { int ret; + if(g_state == CONFIGURATION_ERROR) + return (-1); + ret = rdt_preinit(); if (ret != 0) return ret; diff --git a/src/log_logstash.c b/src/log_logstash.c index 8df32a8e..06059304 100644 --- a/src/log_logstash.c +++ b/src/log_logstash.c @@ -41,8 +41,6 @@ #define HAVE_YAJL_V2 1 #endif -#define DEFAULT_LOGFILE LOCALSTATEDIR "/log/" PACKAGE_NAME ".json.log" - #if COLLECT_DEBUG static int log_level = LOG_DEBUG; #else @@ -149,8 +147,7 @@ static void log_logstash_print(yajl_gen g, int severity, pthread_mutex_lock(&file_lock); if (log_file == NULL) { - fh = fopen(DEFAULT_LOGFILE, "a"); - do_close = 1; + fh = stderr; } else if (strcasecmp(log_file, "stdout") == 0) { fh = stdout; do_close = 0; @@ -164,8 +161,7 @@ static void log_logstash_print(yajl_gen g, int severity, if (fh == NULL) { char errbuf[1024]; - fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", - (log_file == NULL) ? DEFAULT_LOGFILE : log_file, + fprintf(stderr, "log_logstash plugin: fopen (%s) failed: %s\n", log_file, sstrerror(errno, errbuf, sizeof(errbuf))); } else { fprintf(fh, "%s\n", buf); diff --git a/src/logfile.c b/src/logfile.c index 0de639e9..eca8c347 100644 --- a/src/logfile.c +++ b/src/logfile.c @@ -31,8 +31,6 @@ #include "common.h" #include "plugin.h" -#define DEFAULT_LOGFILE LOCALSTATEDIR "/log/collectd.log" - #if COLLECT_DEBUG static int log_level = LOG_DEBUG; #else @@ -117,8 +115,7 @@ static void logfile_print(const char *msg, int severity, pthread_mutex_lock(&file_lock); if (log_file == NULL) { - fh = fopen(DEFAULT_LOGFILE, "a"); - do_close = 1; + fh = stderr; } else if (strcasecmp(log_file, "stderr") == 0) fh = stderr; else if (strcasecmp(log_file, "stdout") == 0) @@ -130,8 +127,7 @@ static void logfile_print(const char *msg, int severity, if (fh == NULL) { char errbuf[1024]; - fprintf(stderr, "logfile plugin: fopen (%s) failed: %s\n", - (log_file == NULL) ? DEFAULT_LOGFILE : log_file, + fprintf(stderr, "logfile plugin: fopen (%s) failed: %s\n", log_file, sstrerror(errno, errbuf, sizeof(errbuf))); } else { if (print_timestamp) diff --git a/src/mcelog.c b/src/mcelog.c index 6dbfafce..4e6a6fd1 100644 --- a/src/mcelog.c +++ b/src/mcelog.c @@ -42,8 +42,8 @@ #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:" +#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 */ @@ -64,8 +64,8 @@ struct socket_adapter_s { }; typedef struct mcelog_memory_rec_s { - int corrected_err_total; /* x total*/ - int corrected_err_timed; /* x in 24h*/ + 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*/ @@ -80,9 +80,7 @@ static int socket_write(socket_adapter_t *self, const char *msg, 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 mcelog_config_t g_mcelog_config = {.logfile = "/var/log/mcelog"}; static socket_adapter_t socket_adapter = { .sock_fd = -1, @@ -97,7 +95,7 @@ static socket_adapter_t socket_adapter = { .receive = socket_receive, }; -static _Bool mcelog_thread_running = 0; +static _Bool mcelog_thread_running; static int mcelog_config(oconfig_item_t *ci) { for (int i = 0; i < ci->children_num; i++) { @@ -106,21 +104,21 @@ static int mcelog_config(oconfig_item_t *ci) { 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, + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", child->key); - return -1; + 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, + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", child->key); - return -1; + return (-1); } } else { - ERROR("%s: Invalid configuration option: \"%s\".", MCELOG_PLUGIN, + ERROR(MCELOG_PLUGIN ": Invalid configuration option: \"%s\".", child->key); - return -1; + return (-1); } } return (0); @@ -130,16 +128,20 @@ static int socket_close(socket_adapter_t *self) { int ret = 0; pthread_rwlock_rdlock(&self->lock); if (fcntl(self->sock_fd, F_GETFL) != -1) { + char errbuf[MCELOG_BUFF_SIZE]; if (shutdown(self->sock_fd, SHUT_RDWR) != 0) { - char errbuf[MCELOG_BUFF_SIZE]; - ERROR("%s: Socket shutdown failed: %s", MCELOG_PLUGIN, + ERROR(MCELOG_PLUGIN ": Socket shutdown failed: %s", + sstrerror(errno, errbuf, sizeof(errbuf))); + ret = -1; + } + if (close(self->sock_fd) != 0) { + ERROR(MCELOG_PLUGIN ": Socket close failed: %s", sstrerror(errno, errbuf, sizeof(errbuf))); ret = -1; } - close(self->sock_fd); } pthread_rwlock_unlock(&self->lock); - return ret; + return (ret); } static int socket_write(socket_adapter_t *self, const char *msg, @@ -149,7 +151,20 @@ static int socket_write(socket_adapter_t *self, const char *msg, if (swrite(self->sock_fd, msg, len) < 0) ret = -1; pthread_rwlock_unlock(&self->lock); - return ret; + return (ret); +} + +static void mcelog_dispatch_notification(notification_t *n) { + if (!n) { + ERROR(MCELOG_PLUGIN ": %s: NULL pointer", __FUNCTION__); + return; + } + + sstrncpy(n->host, hostname_g, sizeof(n->host)); + sstrncpy(n->type, "gauge", sizeof(n->type)); + plugin_dispatch_notification(n); + if (n->meta) + plugin_notification_meta_free(n->meta); } static int socket_reinit(socket_adapter_t *self) { @@ -160,18 +175,19 @@ static int socket_reinit(socket_adapter_t *self) { /* 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); + 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, + ERROR(MCELOG_PLUGIN ": Could not create a socket. %s", sstrerror(errno, errbuff, sizeof(errbuff))); pthread_rwlock_unlock(&self->lock); - return ret; + 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); + if (setsockopt(self->sock_fd, SOL_SOCKET, SO_SNDTIMEO, &socket_timeout, + sizeof(socket_timeout)) < 0) + ERROR(MCELOG_PLUGIN ": Failed to set the socket timeout option."); /* downgrading to read lock due to possible recursive read locks * in self->close(self) call */ @@ -179,109 +195,126 @@ static int socket_reinit(socket_adapter_t *self) { 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, + ERROR(MCELOG_PLUGIN ": Failed to connect to mcelog server. %s", sstrerror(errno, errbuff, sizeof(errbuff))); self->close(self); ret = -1; - } else + } else { ret = 0; - + mcelog_dispatch_notification( + &(notification_t){.severity = NOTIF_OKAY, + .time = cdtime(), + .message = "Connected to mcelog server", + .plugin = MCELOG_PLUGIN, + .type_instance = "mcelog_status"}); + } 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); + return (ret); } static int mcelog_prepare_notification(notification_t *n, - mcelog_memory_rec_t mr) { - if (n == NULL) + const mcelog_memory_rec_t *mr) { + if (n == NULL || mr == 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); + if ((mr->location[0] != '\0') && + (plugin_notification_meta_add_string(n, MCELOG_SOCKET_STR, mr->location) < + 0)) { + ERROR(MCELOG_PLUGIN ": add memory location meta data failed"); + return (-1); + } + if ((mr->dimm_name[0] != '\0') && + (plugin_notification_meta_add_string(n, MCELOG_DIMM_NAME, mr->dimm_name) < + 0)) { + ERROR(MCELOG_PLUGIN ": add DIMM name meta data failed"); + plugin_notification_meta_free(n->meta); 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); + mr->corrected_err_total) < 0) { + ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed"); + plugin_notification_meta_free(n->meta); 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); + n, "corrected memory timed errors", mr->corrected_err_timed) < 0) { + ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed"); + plugin_notification_meta_free(n->meta); 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); + if ((mr->corrected_err_timed_period[0] != '\0') && + (plugin_notification_meta_add_string(n, "corrected errors time period", + mr->corrected_err_timed_period) < + 0)) { + ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed"); + plugin_notification_meta_free(n->meta); 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); + mr->uncorrected_err_total) < 0) { + ERROR(MCELOG_PLUGIN ": add corrected errors meta data failed"); + plugin_notification_meta_free(n->meta); 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); + if (plugin_notification_meta_add_signed_int(n, + "uncorrected memory timed errors", + mr->uncorrected_err_timed) < 0) { + ERROR(MCELOG_PLUGIN ": add corrected timed errors meta data failed"); + plugin_notification_meta_free(n->meta); 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); + if ((mr->uncorrected_err_timed_period[0] != '\0') && + (plugin_notification_meta_add_string(n, "uncorrected errors time period", + mr->uncorrected_err_timed_period) < + 0)) { + ERROR(MCELOG_PLUGIN ": add corrected errors period meta data failed"); + plugin_notification_meta_free(n->meta); return (-1); } return (0); } -static int mcelog_submit(mcelog_memory_rec_t mr) { +static int mcelog_submit(const mcelog_memory_rec_t *mr) { + + if (!mr) { + ERROR(MCELOG_PLUGIN ": %s: NULL pointer", __FUNCTION__); + return (-1); + } - value_list_t vl = VALUE_LIST_INIT; - vl.values_len = 1; - vl.time = cdtime(); + value_list_t vl = { + .values_len = 1, + .values = &(value_t){.derive = (derive_t)mr->corrected_err_total}, + .time = cdtime(), + .plugin = MCELOG_PLUGIN, + .type = "errors", + .type_instance = "corrected_memory_errors"}; - sstrncpy(vl.plugin, MCELOG_PLUGIN, sizeof(vl.plugin)); - sstrncpy(vl.type, "errors", sizeof(vl.type)); - if (strlen(mr.dimm_name) > 0) { + if (mr->dimm_name[0] != '\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)); + 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}; + "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}; + 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}; + "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; + return (0); } static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { @@ -290,7 +323,7 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { /* Got empty line or "done" */ if ((!strncmp("\n", buf, strlen(buf))) || (!strncmp(buf, "done\n", strlen(buf)))) - return 1; + return (1); if (strlen(buf) < 5) continue; if (!strncmp(buf, MCELOG_SOCKET_STR, strlen(MCELOG_SOCKET_STR))) { @@ -299,7 +332,7 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { 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); + DEBUG(MCELOG_PLUGIN ": Got SOCKET INFO %s", memory_record->location); } if (!strncmp(buf, MCELOG_DIMM_NAME, strlen(MCELOG_DIMM_NAME))) { char *name = NULL; @@ -310,8 +343,7 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { 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); + DEBUG(MCELOG_PLUGIN ": Got DIMM NAME %s", memory_record->dimm_name); } } } @@ -319,13 +351,13 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { /* 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, + DEBUG(MCELOG_PLUGIN ": Got corrected error total %d", 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, + DEBUG(MCELOG_PLUGIN ": Got timed corrected errors %d in %s", memory_record->corrected_err_total, memory_record->corrected_err_timed_period); } @@ -333,13 +365,13 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { 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, + DEBUG(MCELOG_PLUGIN ": Got uncorrected error total %d", 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, + DEBUG(MCELOG_PLUGIN ": Got timed uncorrected errors %d in %s", memory_record->uncorrected_err_total, memory_record->uncorrected_err_timed_period); } @@ -347,7 +379,7 @@ static int parse_memory_info(FILE *p_file, mcelog_memory_rec_t *memory_record) { memset(buf, 0, sizeof(buf)); } /* parsing definitely finished */ - return 0; + return (0); } static void poll_worker_cleanup(void *arg) { @@ -372,35 +404,35 @@ static int socket_receive(socket_adapter_t *self, FILE **pp_file) { sstrerror(errno, errbuf, sizeof(errbuf))); } pthread_rwlock_unlock(&self->lock); - return res; + return (res); } if (poll_fd.revents & (POLLERR | POLLHUP | POLLNVAL)) { /* connection is broken */ - ERROR("%s: Connection to socket is broken", MCELOG_PLUGIN); + ERROR(MCELOG_PLUGIN ": Connection to socket is broken"); 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); + mcelog_dispatch_notification( + &(notification_t){.severity = NOTIF_FAILURE, + .time = cdtime(), + .message = "Connection to mcelog socket is broken.", + .plugin = MCELOG_PLUGIN, + .type_instance = "mcelog_status"}); } pthread_rwlock_unlock(&self->lock); - return -1; + return (-1); } if (!(poll_fd.revents & (POLLIN | POLLPRI))) { - INFO("%s: No data to read", MCELOG_PLUGIN); + INFO(MCELOG_PLUGIN ": No data to read"); pthread_rwlock_unlock(&self->lock); - return 0; + return (0); } if ((*pp_file = fdopen(dup(self->sock_fd), "r")) == NULL) res = -1; pthread_rwlock_unlock(&self->lock); - return res; + return (res); } static void *poll_worker(__attribute__((unused)) void *arg) { @@ -416,14 +448,13 @@ static void *poll_worker(__attribute__((unused)) void *arg) { pthread_cleanup_push(poll_worker_cleanup, pp_file); while (1) { - int res = 0; /* blocking call */ - res = socket_adapter.receive(&socket_adapter, pp_file); + int 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); + while (socket_adapter.reinit(&socket_adapter) != 0) { + nanosleep(&CDTIME_T_TO_TIMESPEC(MS_TO_CDTIME_T(MCELOG_POLL_TIMEOUT)), + NULL); } continue; } @@ -436,14 +467,22 @@ static void *poll_worker(__attribute__((unused)) void *arg) { 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); + /* Check if location was successfully parsed */ + if (memory_record.location[0] == '\0') { + memset(&memory_record, 0, sizeof(memory_record)); + continue; + } + + notification_t n = {.severity = NOTIF_OKAY, + .time = cdtime(), + .message = "Got memory errors info.", + .plugin = MCELOG_PLUGIN, + .type_instance = "memory_erros"}; + + if (mcelog_prepare_notification(&n, &memory_record) == 0) + mcelog_dispatch_notification(&n); + if (mcelog_submit(&memory_record) != 0) + ERROR(MCELOG_PLUGIN ": Failed to submit memory errors"); memset(&memory_record, 0, sizeof(memory_record)); } @@ -453,40 +492,40 @@ static void *poll_worker(__attribute__((unused)) void *arg) { mcelog_thread_running = 0; pthread_cleanup_pop(1); - return NULL; + 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; + ERROR(MCELOG_PLUGIN ": Cannot connect to client socket"); + 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; + ERROR(MCELOG_PLUGIN ": Error creating poll thread."); + return (-1); } - return 0; + 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); + ERROR(MCELOG_PLUGIN ": SENT DUMP REQUEST FAILED"); else - DEBUG("%s: SENT DUMP REQUEST OK", MCELOG_PLUGIN); - return ret; + DEBUG(MCELOG_PLUGIN ": SENT DUMP REQUEST OK"); + return (ret); } static int mcelog_read(__attribute__((unused)) user_data_t *ud) { - DEBUG("%s: %s", MCELOG_PLUGIN, __FUNCTION__); + DEBUG(MCELOG_PLUGIN ": %s", __FUNCTION__); if (get_memory_machine_checks() != 0) - ERROR("%s: MACHINE CHECK INFO NOT AVAILABLE", MCELOG_PLUGIN); + ERROR(MCELOG_PLUGIN ": MACHINE CHECK INFO NOT AVAILABLE"); - return 0; + return (0); } static int mcelog_shutdown(void) { @@ -494,14 +533,14 @@ static int mcelog_shutdown(void) { 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); + ERROR(MCELOG_PLUGIN ": Stopping thread failed."); ret = -1; } } ret = socket_adapter.close(&socket_adapter) || ret; pthread_rwlock_destroy(&(socket_adapter.lock)); - return -ret; + return (-ret); } void module_register(void) { diff --git a/src/mqtt.c b/src/mqtt.c index 33785c8f..a962514c 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -448,6 +448,7 @@ static int publish(mqtt_client_conf_t *conf, char const *topic, * measure; we will try to reconnect the next time we have to publish a * message */ conf->connected = 0; + mosquitto_disconnect(conf->mosq); pthread_mutex_unlock(&conf->lock); return (-1); @@ -461,6 +462,7 @@ static int format_topic(char *buf, size_t buf_len, data_set_t const *ds, value_list_t const *vl, mqtt_client_conf_t *conf) { char name[MQTT_MAX_TOPIC_SIZE]; int status; + char *c; if ((conf->topic_prefix == NULL) || (conf->topic_prefix[0] == 0)) return (FORMAT_VL(buf, buf_len, vl)); @@ -473,6 +475,10 @@ static int format_topic(char *buf, size_t buf_len, data_set_t const *ds, if ((status < 0) || (((size_t)status) >= buf_len)) return (ENOMEM); + while((c = strchr(buf, '#')) || (c = strchr(buf, '+'))) { + *c = '_'; + } + return (0); } /* int format_topic */ diff --git a/src/nut.c b/src/nut.c index c0ee7abf..5acbdde6 100644 --- a/src/nut.c +++ b/src/nut.c @@ -54,8 +54,11 @@ static nut_ups_t *upslist_head = NULL; static pthread_mutex_t read_lock = PTHREAD_MUTEX_INITIALIZER; static int read_busy = 0; -static const char *config_keys[] = {"UPS"}; +static const char *config_keys[] = {"UPS", "FORCESSL", "VERIFYPEER", "CAPATH"}; static int config_keys_num = STATIC_ARRAY_SIZE(config_keys); +static int force_ssl = 0; // Initialized to default of 0 (false) +static int verify_peer = 0; // Initialized to default of 0 (false) +static char *ca_path = NULL; static void free_nut_ups_t(nut_ups_t *ups) { if (ups->conn != NULL) { @@ -98,9 +101,51 @@ static int nut_add_ups(const char *name) { return (0); } /* int nut_add_ups */ +static int nut_force_ssl(const char *value) { + if (strcasecmp(value, "true") == 0) + force_ssl = 1; + else if (strcasecmp(value, "false") == 0) + force_ssl = 0; // Should already be set to 0 from initialization + else { + force_ssl = 0; + WARNING("nut plugin: nut_force_ssl: invalid FORCESSL value " + "found. Defaulting to false."); + } + return (0); +} /* int nut_parse_force_ssl */ + +static int nut_verify_peer(const char *value) { + if (strcasecmp(value, "true") == 0) + verify_peer = 1; + else if (strcasecmp(value, "false") == 0) + verify_peer = 0; // Should already be set to 0 from initialization + else { + verify_peer = 0; + WARNING("nut plugin: nut_verify_peer: invalid VERIFYPEER value " + "found. Defaulting to false."); + } + return (0); +} /* int nut_verify_peer */ + +static int nut_ca_path(const char *value) { + if (value != NULL && strcmp(value, "") != 0) { + ca_path = malloc(strlen(value) + 1); + strncpy(ca_path, value, (strlen(value) + 1)); + } else { + ca_path = NULL; // Should alread be set to NULL from initialization + } + return (0); +} /* int nut_ca_path */ + static int nut_config(const char *key, const char *value) { if (strcasecmp(key, "UPS") == 0) return (nut_add_ups(value)); + else if (strcasecmp(key, "FORCESSL") == 0) + return (nut_force_ssl(value)); + else if (strcasecmp(key, "VERIFYPEER") == 0) + return (nut_verify_peer(value)); + else if (strcasecmp(key, "CAPATH") == 0) + return (nut_ca_path(value)); else return (-1); } /* int nut_config */ @@ -123,6 +168,119 @@ static void nut_submit(nut_ups_t *ups, const char *type, plugin_dispatch_values(&vl); } /* void nut_submit */ +static int nut_connect(nut_ups_t *ups) { +#ifdef WITH_UPSCLIENT_27 + int status; + int ssl_status; + int ssl_flags; + + if (verify_peer == 1 && force_ssl == 0) { + WARNING("nut plugin: nut_connect: VerifyPeer true but ForceSSL " + "false. Setting ForceSSL to true."); + force_ssl = 1; + } + + if (verify_peer == 1 && ca_path == NULL) { + ERROR("nut plugin: nut_connect: VerifyPeer true but missing " + "CAPath value."); + return (-1); + } + + if (verify_peer == 1) { + status = upscli_init(verify_peer, ca_path, NULL, NULL); + + if (status != 1) { + ERROR("nut plugin: nut_connect: upscli_init (%i, %s) failed: %s", + verify_peer, ca_path, upscli_strerror(ups->conn)); + upscli_cleanup(); + return (-1); + } + } /* if (verify_peer == 1) */ + + if (verify_peer == 1) + ssl_flags = (UPSCLI_CONN_REQSSL | UPSCLI_CONN_CERTVERIF); + else if (force_ssl == 1) + ssl_flags = UPSCLI_CONN_REQSSL; + else + ssl_flags = UPSCLI_CONN_TRYSSL; + + status = upscli_connect(ups->conn, ups->hostname, ups->port, ssl_flags); + + if (status != 0) { + ERROR("nut plugin: nut_connect: upscli_connect (%s, %i) failed: %s", + ups->hostname, ups->port, upscli_strerror(ups->conn)); + sfree(ups->conn); + upscli_cleanup(); + return (-1); + } /* if (status != 0) */ + + INFO("nut plugin: Connection to (%s, %i) established.", ups->hostname, + ups->port); + + // Output INFO or WARNING based on SSL and VERIFICATION + ssl_status = upscli_ssl(ups->conn); // 1 for SSL, 0 for not, -1 for error + if (ssl_status == 1 && verify_peer == 1) { + INFO("nut plugin: Connection is secured with SSL and certificate " + "has been verified."); + } else if (ssl_status == 1) { + INFO("nut plugin: Connection is secured with SSL with no verification " + "of server SSL certificate."); + } else if (ssl_status == 0) { + WARNING("nut plugin: Connection is unsecured (no SSL)."); + } else { + ERROR("nut plugin: nut_connect: upscli_ssl failed: %s", + upscli_strerror(ups->conn)); + sfree(ups->conn); + upscli_cleanup(); + return (-1); + } /* if (ssl_status == 1 && verify_peer == 1) */ + return (0); + +#else /* #ifdef WITH_UPSCLIENT_27 */ + int status; + int ssl_status; + int ssl_flags; + + if (verify_peer == 1 || ca_path != NULL) { + WARNING("nut plugin: nut_connect: Dependency libupsclient version " + "insufficient (<2.7) for VerifyPeer support. Ignoring VerifyPeer " + "and CAPath."); + } + + if (force_ssl == 1) + ssl_flags = UPSCLI_CONN_REQSSL; + else + ssl_flags = UPSCLI_CONN_TRYSSL; + + status = upscli_connect(ups->conn, ups->hostname, ups->port, ssl_flags); + + if (status != 0) { + ERROR("nut plugin: nut_connect: upscli_connect (%s, %i) failed: %s", + ups->hostname, ups->port, upscli_strerror(ups->conn)); + sfree(ups->conn); + return (-1); + } /* if (status != 0) */ + + INFO("nut plugin: Connection to (%s, %i) established.", ups->hostname, + ups->port); + + // Output INFO or WARNING based on SSL + ssl_status = upscli_ssl(ups->conn); // 1 for SSL, 0 for not, -1 for error + if (ssl_status == 1) { + INFO("nut plugin: Connection is secured with SSL with no verification " + "of server SSL certificate."); + } else if (ssl_status == 0) { + WARNING("nut plugin: Connection is unsecured (no SSL)."); + } else { + ERROR("nut plugin: nut_connect: upscli_ssl failed: %s", + upscli_strerror(ups->conn)); + sfree(ups->conn); + return (-1); + } /* if (ssl_status == 1 && verify_peer == 1) */ + return (0); +#endif +} + static int nut_read_one(nut_ups_t *ups) { const char *query[3] = {"VAR", ups->upsname, NULL}; unsigned int query_num = 2; @@ -138,17 +296,10 @@ static int nut_read_one(nut_ups_t *ups) { return (-1); } - status = - upscli_connect(ups->conn, ups->hostname, ups->port, UPSCLI_CONN_TRYSSL); - if (status != 0) { - ERROR("nut plugin: nut_read_one: upscli_connect (%s, %i) failed: %s", - ups->hostname, ups->port, upscli_strerror(ups->conn)); - sfree(ups->conn); - return (-1); - } + status = nut_connect(ups); + if (status == -1) + return -1; - INFO("nut plugin: Connection to (%s, %i) established.", ups->hostname, - ups->port); } /* if (ups->conn == NULL) */ /* nut plugin: nut_read_one: upscli_list_start (adpos) failed: Protocol @@ -159,6 +310,9 @@ static int nut_read_one(nut_ups_t *ups) { ups->upsname, upscli_strerror(ups->conn)); upscli_disconnect(ups->conn); sfree(ups->conn); +#ifdef WITH_UPSCLIENT_27 + upscli_cleanup(); +#endif return (-1); } @@ -246,6 +400,9 @@ static int nut_shutdown(void) { free_nut_ups_t(this); this = next; } +#ifdef WITH_UPSCLIENT_27 + upscli_cleanup(); +#endif return (0); } /* int nut_shutdown */ diff --git a/src/ovs_events.c b/src/ovs_events.c index c77bde4a..8c2cd12c 100644 --- a/src/ovs_events.c +++ b/src/ovs_events.c @@ -90,6 +90,9 @@ static ovs_events_ctx_t ovs_events_ctx = { .ovs_db_serv = "6640"} /* use default OVS DB service */ }; +/* Forward declaration */ +static int ovs_events_plugin_read(user_data_t *u); + /* This function is used only by "OVS_EVENTS_CTX_LOCK" define (see above). * It always returns 1 when context is locked. */ @@ -224,6 +227,7 @@ static int ovs_events_config_get_interfaces(const oconfig_item_t *ci) { * in allocated memory. Returns negative value in case of error. */ static int ovs_events_plugin_config(oconfig_item_t *ci) { + _Bool dispatch_values = 1; for (int i = 0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; if (strcasecmp("SendNotification", child->key) == 0) { @@ -260,12 +264,28 @@ static int ovs_events_plugin_config(oconfig_item_t *ci) { ovs_events_config_free(); return (-1); } + } else if (strcasecmp("DispatchValues", child->key) == 0) { + if (cf_util_get_boolean(child, &dispatch_values) != 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); } } + /* Check and warn about invalid configuration */ + if (!ovs_events_ctx.config.send_notification && !dispatch_values) { + WARNING(OVS_EVENTS_PLUGIN ": send notification and dispatch values " + "options are disabled. No information will be dispatched by the " + "plugin. Please check your configuration"); + } + /* Dispatch link status values if configured */ + if (dispatch_values) + return plugin_register_complex_read(NULL, OVS_EVENTS_PLUGIN, + ovs_events_plugin_read, 0, NULL); + return (0); } @@ -633,7 +653,5 @@ static int ovs_events_plugin_shutdown(void) { 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); } diff --git a/src/smart.c b/src/smart.c index 9395945b..3188d1c8 100644 --- a/src/smart.c +++ b/src/smart.c @@ -33,6 +33,10 @@ #include #include +#ifdef HAVE_SYS_CAPABILITY_H +#include +#endif + static const char *config_keys[] = {"Disk", "IgnoreSelected", "IgnoreSleepMode", "UseSerial"}; @@ -238,7 +242,25 @@ static int smart_read(void) { return (0); } /* int smart_read */ +static int smart_init(void) { +#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_SYS_RAWIO) + if (check_capability(CAP_SYS_RAWIO) != 0) { + if (getuid() == 0) + WARNING("smart plugin: Running collectd as root, but the " + "CAP_SYS_RAWIO capability is missing. The plugin's read " + "function will probably fail. Is your init system dropping " + "capabilities?"); + else + WARNING("smart plugin: collectd doesn't have the CAP_SYS_RAWIO " + "capability. If you don't want to run collectd as root, try " + "running \"setcap cap_sys_rawio=ep\" on the collectd binary."); + } +#endif + return (0); +} /* int smart_init */ + void module_register(void) { plugin_register_config("smart", smart_config, config_keys, config_keys_num); + plugin_register_init("smart", smart_init); plugin_register_read("smart", smart_read); } /* void module_register */ diff --git a/src/utils_dpdk.c b/src/utils_dpdk.c index 640f08bc..e3c73793 100644 --- a/src/utils_dpdk.c +++ b/src/utils_dpdk.c @@ -38,6 +38,7 @@ #include #include +#include #include "common.h" #include "utils_dpdk.h" @@ -850,3 +851,22 @@ uint128_t str_to_uint128(const char *str, int len) { } return lcore_mask; } + +uint8_t dpdk_helper_eth_dev_count() { + uint8_t ports = rte_eth_dev_count(); + if (ports == 0) { + ERROR( + "%s:%d: No DPDK ports available. Check bound devices to DPDK driver.\n", + __FUNCTION__, __LINE__); + return ports; + } + + if (ports > RTE_MAX_ETHPORTS) { + ERROR("%s:%d: Number of DPDK ports (%u) is greater than " + "RTE_MAX_ETHPORTS=%d. Ignoring extra ports\n", + __FUNCTION__, __LINE__, ports, RTE_MAX_ETHPORTS); + ports = RTE_MAX_ETHPORTS; + } + + return ports; +} diff --git a/src/utils_dpdk.h b/src/utils_dpdk.h index c9bb14b0..f97a6b51 100644 --- a/src/utils_dpdk.h +++ b/src/utils_dpdk.h @@ -73,6 +73,7 @@ int dpdk_helper_command(dpdk_helper_ctx_t *phc, enum DPDK_CMD cmd, int *result, cdtime_t cmd_wait_time); void *dpdk_helper_priv_get(dpdk_helper_ctx_t *phc); int dpdk_helper_data_size_get(dpdk_helper_ctx_t *phc); +uint8_t dpdk_helper_eth_dev_count(); /* forward declaration of handler function that is called by helper from * child process. not implemented in helper. must be provided by client. */ diff --git a/src/utils_match.c b/src/utils_match.c index e2f29808..e8add2d8 100644 --- a/src/utils_match.c +++ b/src/utils_match.c @@ -34,6 +34,7 @@ #include #define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02 +#define UTILS_MATCH_FLAGS_REGEX 0x04 struct cu_match_s { regex_t regex; @@ -234,6 +235,7 @@ match_create_callback(const char *regex, const char *excluderegex, sfree(obj); return (NULL); } + obj->flags |= UTILS_MATCH_FLAGS_REGEX; if (excluderegex && strcmp(excluderegex, "") != 0) { status = regcomp(&obj->excluderegex, excluderegex, REG_EXTENDED); @@ -301,6 +303,10 @@ void match_destroy(cu_match_t *obj) { if (obj == NULL) return; + if (obj->flags & UTILS_MATCH_FLAGS_REGEX) + regfree(&obj->regex); + if (obj->flags & UTILS_MATCH_FLAGS_EXCLUDE_REGEX) + regfree(&obj->excluderegex); if ((obj->user_data != NULL) && (obj->free != NULL)) (*obj->free)(obj->user_data); diff --git a/src/virt.c b/src/virt.c index 830db513..692088c4 100644 --- a/src/virt.c +++ b/src/virt.c @@ -37,6 +37,18 @@ /* Plugin name */ #define PLUGIN_NAME "virt" +#ifdef LIBVIR_CHECK_VERSION + +#if LIBVIR_CHECK_VERSION(0, 9, 5) +#define HAVE_BLOCK_STATS_FLAGS 1 +#endif + +#if LIBVIR_CHECK_VERSION(0, 9, 11) +#define HAVE_CPU_STATS 1 +#endif + +#endif /* LIBVIR_CHECK_VERSION */ + static const char *config_keys[] = {"Connection", "RefreshInterval", @@ -54,6 +66,7 @@ static const char *config_keys[] = {"Connection", "PluginInstanceFormat", "Instances", + "ExtraStats", NULL}; #define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1) @@ -158,6 +171,19 @@ enum bd_field { target, source }; /* InterfaceFormat. */ enum if_field { if_address, if_name, if_number }; +/* ExtraStats */ +#define EX_STATS_MAX_FIELDS 8 +enum ex_stats { ex_stats_none = 0, ex_stats_disk = 1, ex_stats_pcpu = 2 }; +static unsigned int extra_stats = ex_stats_none; + +struct ex_stats_item { + const char *name; + enum ex_stats flag; +}; +static const struct ex_stats_item ex_stats_table[] = { + {"disk", ex_stats_disk}, {"pcpu", ex_stats_pcpu}, {NULL, ex_stats_none}, +}; + /* BlockDeviceFormatBasename */ _Bool blockdevice_format_basename = 0; static enum bd_field blockdevice_format = target; @@ -168,6 +194,71 @@ static time_t last_refresh = (time_t)0; static int refresh_lists(struct lv_read_instance *inst); +struct lv_info { + virDomainInfo di; + unsigned long long total_user_cpu_time; + unsigned long long total_syst_cpu_time; +}; + +struct lv_block_info { + virDomainBlockStatsStruct bi; + + long long rd_total_times; + long long wr_total_times; + + long long fl_req; + long long fl_total_times; +}; + +static void init_block_info(struct lv_block_info *binfo) { + if (binfo == NULL) + return; + + binfo->bi.rd_req = -1; + binfo->bi.wr_req = -1; + binfo->bi.rd_bytes = -1; + binfo->bi.wr_bytes = -1; + + binfo->rd_total_times = -1; + binfo->wr_total_times = -1; + binfo->fl_req = -1; + binfo->fl_total_times = -1; +} + +#ifdef HAVE_BLOCK_STATS_FLAGS + +#define GET_BLOCK_INFO_VALUE(NAME, FIELD) \ + do { \ + if (!strcmp(param[i].field, NAME)) { \ + binfo->FIELD = param[i].value.l; \ + continue; \ + } \ + } while (0) + +static int get_block_info(struct lv_block_info *binfo, + virTypedParameterPtr param, int nparams) { + if (binfo == NULL || param == NULL) + return -1; + + for (int i = 0; i < nparams; ++i) { + /* ignore type. Everything must be LLONG anyway. */ + GET_BLOCK_INFO_VALUE("rd_operations", bi.rd_req); + GET_BLOCK_INFO_VALUE("wr_operations", bi.wr_req); + GET_BLOCK_INFO_VALUE("rd_bytes", bi.rd_bytes); + GET_BLOCK_INFO_VALUE("wr_bytes", bi.wr_bytes); + GET_BLOCK_INFO_VALUE("rd_total_times", rd_total_times); + GET_BLOCK_INFO_VALUE("wr_total_times", wr_total_times); + GET_BLOCK_INFO_VALUE("flush_operations", fl_req); + GET_BLOCK_INFO_VALUE("flush_total_times", fl_total_times); + } + + return 0; +} + +#undef GET_BLOCK_INFO_VALUE + +#endif /* HAVE_BLOCK_STATS_FLAGS */ + /* ERROR(...) macro for virterrors. */ #define VIRT_ERROR(conn, s) \ do { \ @@ -177,6 +268,54 @@ static int refresh_lists(struct lv_read_instance *inst); ERROR("%s: %s", (s), err->message); \ } while (0) +static void init_lv_info(struct lv_info *info) { + if (info != NULL) + memset(info, 0, sizeof(*info)); +} + +static int lv_domain_info(virDomainPtr dom, struct lv_info *info) { +#ifdef HAVE_CPU_STATS + virTypedParameterPtr param = NULL; + int nparams = 0; +#endif /* HAVE_CPU_STATS */ + int ret = virDomainGetInfo(dom, &(info->di)); + if (ret != 0) { + return ret; + } + +#ifdef HAVE_CPU_STATS + nparams = virDomainGetCPUStats(dom, NULL, 0, -1, 1, 0); + if (nparams < 0) { + VIRT_ERROR(conn, "getting the CPU params count"); + return -1; + } + + param = calloc(nparams, sizeof(virTypedParameter)); + if (param == NULL) { + ERROR("virt plugin: alloc(%i) for cpu parameters failed.", nparams); + return -1; + } + + ret = virDomainGetCPUStats(dom, param, nparams, -1, 1, 0); // total stats. + if (ret < 0) { + virTypedParamsFree(param, nparams); + VIRT_ERROR(conn, "getting the disk params values"); + return -1; + } + + for (int i = 0; i < nparams; ++i) { + if (!strcmp(param[i].field, "user_time")) + info->total_user_cpu_time = param[i].value.ul; + else if (!strcmp(param[i].field, "system_time")) + info->total_syst_cpu_time = param[i].value.ul; + } + + virTypedParamsFree(param, nparams); +#endif /* HAVE_CPU_STATS */ + + return 0; +} + static void init_value_list(value_list_t *vl, virDomainPtr dom) { int n; const char *name; @@ -283,6 +422,23 @@ static void memory_stats_submit(gauge_t value, virDomainPtr dom, submit(dom, "memory", tags[tag_index], &(value_t){.gauge = value}, 1); } +static void submit_derive2(const char *type, derive_t v0, derive_t v1, + virDomainPtr dom, const char *devname) { + value_t values[] = { + {.derive = v0}, {.derive = v1}, + }; + + submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values)); +} /* void submit_derive2 */ + +static void pcpu_submit(virDomainPtr dom, struct lv_info *info) { +#ifdef HAVE_CPU_STATS + if (extra_stats & ex_stats_pcpu) + submit_derive2("ps_cputime", info->total_user_cpu_time, + info->total_syst_cpu_time, dom, NULL); +#endif /* HAVE_CPU_STATS */ +} + static void cpu_submit(unsigned long long value, virDomainPtr dom, const char *type) { submit(dom, type, NULL, &(value_t){.derive = (derive_t)value}, 1); @@ -297,14 +453,51 @@ static void vcpu_submit(derive_t value, virDomainPtr dom, int vcpu_nr, submit(dom, type, type_instance, &(value_t){.derive = value}, 1); } -static void submit_derive2(const char *type, derive_t v0, derive_t v1, - virDomainPtr dom, const char *devname) { - value_t values[] = { - {.derive = v0}, {.derive = v1}, - }; +static void disk_submit(struct lv_block_info *binfo, virDomainPtr dom, + const char *type_instance) { + char flush_type_instance[DATA_MAX_NAME_LEN]; + + ssnprintf(flush_type_instance, sizeof(flush_type_instance), "flush-%s", + type_instance); + + if ((binfo->bi.rd_req != -1) && (binfo->bi.wr_req != -1)) + submit_derive2("disk_ops", (derive_t)binfo->bi.rd_req, + (derive_t)binfo->bi.wr_req, dom, type_instance); + + if ((binfo->bi.rd_bytes != -1) && (binfo->bi.wr_bytes != -1)) + submit_derive2("disk_octets", (derive_t)binfo->bi.rd_bytes, + (derive_t)binfo->bi.wr_bytes, dom, type_instance); + + if (extra_stats & ex_stats_disk) { + if ((binfo->rd_total_times != -1) && (binfo->wr_total_times != -1)) + submit_derive2("disk_time", (derive_t)binfo->rd_total_times, + (derive_t)binfo->wr_total_times, dom, type_instance); + + if (binfo->fl_req != -1) + submit(dom, "total_requests", flush_type_instance, + &(value_t){.derive = (derive_t)binfo->fl_req}, 1); + if (binfo->fl_total_times != -1) { + derive_t value = binfo->fl_total_times / 1000; // ns -> ms + submit(dom, "total_time_in_ms", flush_type_instance, + &(value_t){.derive = value}, 1); + } + } +} - submit(dom, type, devname, values, STATIC_ARRAY_SIZE(values)); -} /* void submit_derive2 */ +static unsigned int parse_ex_stats_flags(char **exstats, int numexstats) { + unsigned int ex_stats_flags = ex_stats_none; + for (int i = 0; i < numexstats; i++) { + for (int j = 0; ex_stats_table[j].name != NULL; j++) { + if (strcasecmp(exstats[i], ex_stats_table[j].name) == 0) { + DEBUG(PLUGIN_NAME " plugin: enabling extra stats for '%s'", + ex_stats_table[j].name); + ex_stats_flags |= ex_stats_table[j].flag; + break; + } + } + } + return ex_stats_flags; +} static int lv_config(const char *key, const char *value) { if (virInitialize() != 0) @@ -500,6 +693,17 @@ static int lv_config(const char *key, const char *value) { return 0; } + if (strcasecmp(key, "ExtraStats") == 0) { + char *localvalue = strdup(value); + if (localvalue != NULL) { + char *exstats[EX_STATS_MAX_FIELDS]; + int numexstats = + strsplit(localvalue, exstats, STATIC_ARRAY_SIZE(exstats)); + extra_stats = parse_ex_stats_flags(exstats, numexstats); + sfree(localvalue); + } + } + /* Unrecognised option. */ return -1; } @@ -527,6 +731,40 @@ static void lv_disconnect(void) { WARNING(PLUGIN_NAME " plugin: closed connection to libvirt"); } +static int lv_domain_block_info(virDomainPtr dom, const char *path, + struct lv_block_info *binfo) { +#ifdef HAVE_BLOCK_STATS_FLAGS + virTypedParameterPtr params = NULL; + int nparams = 0; + int rc = -1; + int ret = virDomainBlockStatsFlags(dom, path, NULL, &nparams, 0); + if (ret < 0 || nparams == 0) { + VIRT_ERROR(conn, "getting the disk params count"); + return -1; + } + + params = calloc(nparams, sizeof(virTypedParameter)); + if (params == NULL) { + ERROR("virt plugin: alloc(%i) for block=%s parameters failed.", nparams, + path); + return -1; + } + ret = virDomainBlockStatsFlags(dom, path, params, &nparams, 0); + if (ret < 0) { + VIRT_ERROR(conn, "getting the disk params values"); + goto done; + } + + rc = get_block_info(binfo, params, nparams); + +done: + virTypedParamsFree(params, nparams); + return rc; +#else + return virDomainBlockStats(dom, path, &(binfo->bi), sizeof(binfo->bi)); +#endif /* HAVE_BLOCK_STATS_FLAGS */ +} + static int lv_read(user_data_t *ud) { time_t t; struct lv_read_instance *inst = NULL; @@ -573,33 +811,30 @@ static int lv_read(user_data_t *ud) { /* Get CPU usage, memory, VCPU usage for each domain. */ for (int i = 0; i < state->nr_domains; ++i) { - virDomainInfo info; + struct lv_info info; virVcpuInfoPtr vinfo = NULL; virDomainMemoryStatPtr minfo = NULL; int status; - status = virDomainGetInfo(state->domains[i], &info); + init_lv_info(&info); + status = lv_domain_info(state->domains[i], &info); if (status != 0) { ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", status); continue; } - if (info.state != VIR_DOMAIN_RUNNING) { - /* only gather stats for running domains */ - continue; - } + pcpu_submit(state->domains[i], &info); + cpu_submit(info.di.cpuTime, state->domains[i], "virt_cpu_total"); + memory_submit((gauge_t)info.di.memory * 1024, state->domains[i]); - cpu_submit(info.cpuTime, state->domains[i], "virt_cpu_total"); - memory_submit((gauge_t)info.memory * 1024, state->domains[i]); - - vinfo = malloc(info.nrVirtCpu * sizeof(vinfo[0])); + vinfo = malloc(info.di.nrVirtCpu * sizeof(vinfo[0])); if (vinfo == NULL) { ERROR(PLUGIN_NAME " plugin: malloc failed."); continue; } - status = virDomainGetVcpus(state->domains[i], vinfo, info.nrVirtCpu, + status = virDomainGetVcpus(state->domains[i], vinfo, info.di.nrVirtCpu, /* cpu map = */ NULL, /* cpu map length = */ 0); if (status < 0) { ERROR(PLUGIN_NAME " plugin: virDomainGetVcpus failed with status %i.", @@ -608,7 +843,7 @@ static int lv_read(user_data_t *ud) { continue; } - for (int j = 0; j < info.nrVirtCpu; ++j) + for (int j = 0; j < info.di.nrVirtCpu; ++j) vcpu_submit(vinfo[j].cpuTime, state->domains[i], vinfo[j].number, "virt_vcpu"); @@ -640,29 +875,29 @@ static int lv_read(user_data_t *ud) { /* Get block device stats for each domain. */ for (int i = 0; i < state->nr_block_devices; ++i) { - struct _virDomainBlockStats stats; + struct block_device *bdev = &(state->block_devices[i]); + struct lv_block_info binfo; + init_block_info(&binfo); - if (virDomainBlockStats(state->block_devices[i].dom, - state->block_devices[i].path, &stats, - sizeof stats) != 0) + if (lv_domain_block_info(bdev->dom, bdev->path, &binfo) < 0) continue; - char *type_instance = NULL; - if (blockdevice_format_basename && blockdevice_format == source) - type_instance = strdup(basename(state->block_devices[i].path)); - else - type_instance = strdup(state->block_devices[i].path); - - if ((stats.rd_req != -1) && (stats.wr_req != -1)) - submit_derive2("disk_ops", (derive_t)stats.rd_req, (derive_t)stats.wr_req, - state->block_devices[i].dom, type_instance); + char *type_instance = bdev->path; + char *path = NULL; + if (blockdevice_format_basename && blockdevice_format == source) { + path = strdup(bdev->path); + if (path == NULL) { + WARNING(PLUGIN_NAME + " plugin: error extracting the basename for '%s', skipped", + bdev->path); + continue; + } + type_instance = basename(path); + } - if ((stats.rd_bytes != -1) && (stats.wr_bytes != -1)) - submit_derive2("disk_octets", (derive_t)stats.rd_bytes, - (derive_t)stats.wr_bytes, state->block_devices[i].dom, - type_instance); + disk_submit(&binfo, bdev->dom, type_instance); - sfree(type_instance); + sfree(path); } /* for (nr_block_devices) */ /* Get interface stats for each domain. */ @@ -889,6 +1124,8 @@ static int refresh_lists(struct lv_read_instance *inst) { xmlXPathContextPtr xpath_ctx = NULL; xmlXPathObjectPtr xpath_obj = NULL; char tag[PARTITION_TAG_MAX_LEN] = {'\0'}; + virDomainInfo info; + int status; dom = virDomainLookupByID(conn, domids[i]); if (dom == NULL) { @@ -903,6 +1140,18 @@ static int refresh_lists(struct lv_read_instance *inst) { goto cont; } + status = virDomainGetInfo(dom, &info); + if (status != 0) { + ERROR(PLUGIN_NAME " plugin: virDomainGetInfo failed with status %i.", + status); + continue; + } + + if (info.state != VIR_DOMAIN_RUNNING) { + DEBUG(PLUGIN_NAME " plugin: skipping inactive domain %s", name); + continue; + } + if (il_domains && ignorelist_match(il_domains, name) != 0) goto cont; diff --git a/src/write_riemann_threshold.c b/src/write_riemann_threshold.c index 992d8562..8f6b4bed 100644 --- a/src/write_riemann_threshold.c +++ b/src/write_riemann_threshold.c @@ -34,8 +34,6 @@ #include "utils_threshold.h" #include "write_riemann_threshold.h" -#include - /* * Threshold management * ==================== diff --git a/version-gen.sh b/version-gen.sh index 2083ec38..bdbb847a 100755 --- a/version-gen.sh +++ b/version-gen.sh @@ -1,6 +1,6 @@ #!/bin/sh -DEFAULT_VERSION="5.7.0.git" +DEFAULT_VERSION="5.7.1.git" if [ -d .git ]; then VERSION="`git describe --dirty=+ --abbrev=7 2> /dev/null | grep collectd | sed -e 's/^collectd-//' -e 's/-/./g'`"