ovs_stats: Implement OVS statistics plugin.
Stefan Hacker <stefan.hacker at web.de>
- teamspeak2 plugin.
+Steven Bell <stv.bell07 at gmail.com>
+ - nut plugin.
+
Sven Trenkel <collectd at semidefinite.de>
- netapp plugin.
- python plugin.
+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
pkglib_LTLIBRARIES += chrony.la
chrony_la_SOURCES = src/chrony.c
chrony_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+chrony_la_LIBADD = -lm
endif
if BUILD_PLUGIN_CONNTRACK
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
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
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;
{
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 */
)
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
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 <rte_version.h>
+ #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
# }}}
fi
if test "x$with_libpqos" = "xyes"
then
+ SAVE_CPPFLAGS="$CPPFLAGS"
+ CPPFLAGS="$CPPFLAGS $with_libpqos_cppflags"
+ AC_RUN_IFELSE([AC_LANG_PROGRAM(
+ [[#include <pqos.h>]],
+ [[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"
[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
plugin_df="no"
plugin_disk="no"
plugin_drbd="no"
+plugin_dpdkevents="no"
plugin_dpdkstat="no"
plugin_entropy="no"
plugin_ethstat="no"
if test "x$with_libdpdk" = "xyes"
then
+ plugin_dpdkevents="$dpdk_keepalive"
plugin_dpdkstat="yes"
fi
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])
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])
%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}}
%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
%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
%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 <collectd@verplant.org>
%if 0%{?fedora} || 0%{?rhel} >= 7
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
%doc contrib/
%changelog
+* Wed Feb 22 2017 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.1-2
+- Enable XFS support in df plugin
+- Fix bogus date in changelog
+
+* Sun Jan 01 2017 Marc Fournier <marc.fournier@camptocamp.com> - 5.7.1-1
+- New upstream version
+
* Sat Dec 31 2016 Ruben Kerkhof <ruben@rubenkerkhof.com> - 5.7.0-4
- Add new ovs_events plugin
# 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:
#@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
# SelectNumericQueryTypes true
#</Plugin>
+#<Plugin "dpdkevents">
+# <EAL>
+# Coremask "0x1"
+# MemoryChannels "4"
+# ProcessType "secondary"
+# FilePrefix "rte"
+# </EAL>
+# <Event "link_status">
+# SendEventsOnUpdate true
+# EnabledPortMask 0xffff
+# PortName "interface1"
+# PortName "interface2"
+# SendNotification false
+# </Event>
+# <Event "keep_alive">
+# SendEventsOnUpdate true
+# LCoreMask "0xf"
+# KeepAliveShmName "/dpdk_keepalive_shm_name"
+# SendNotification false
+# </Event>
+#</Plugin>
+
#<Plugin dpdkstat>
# <EAL>
# Coremask "0x2"
# ProcessType "secondary"
# FilePrefix "rte"
# </EAL>
+# SharedMemObj "dpdk_collectd_stats_0"
# EnabledPortMask 0xffff
# PortName "interface1"
# PortName "interface2"
#<Plugin nut>
# UPS "upsname@hostname:port"
+# ForceSSL true
+# VerifyPeer true
+# CAPath "/path/to/folder"
#</Plugin>
#<Plugin olsrd>
# Socket "/var/run/openvswitch/db.sock"
# Interfaces "br0" "veth0"
# SendNotification false
+# DispatchValues true
#</Plugin>
#<Plugin ovs_stats>
# InterfaceFormat name
# PluginInstanceFormat name
# Instances 1
+# ExtraStats "disk pcpu"
#</Plugin>
#<Plugin vmem>
=back
+=head2 Plugin C<dpdkevents>
+
+The I<dpdkevents plugin> 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<Synopsis:>
+
+ <Plugin "dpdkevents">
+ <EAL>
+ Coremask "0x1"
+ MemoryChannels "4"
+ ProcessType "secondary"
+ FilePrefix "rte"
+ </EAL>
+ <Event "link_status">
+ SendEventsOnUpdate true
+ EnabledPortMask 0xffff
+ PortName "interface1"
+ PortName "interface2"
+ SendNotification false
+ </Event>
+ <Event "keep_alive">
+ SendEventsOnUpdate true
+ LCoreMask "0xf"
+ KeepAliveShmName "/dpdk_keepalive_shm_name"
+ SendNotification false
+ </Event>
+ </Plugin>
+
+B<Options:>
+
+
+=head3 The EAL block
+
+=over 5
+
+=item B<Coremask> I<Mask>
+
+=item B<Memorychannels> I<Channels>
+
+Number of memory channels per processor socket.
+
+=item B<ProcessType> I<type>
+
+The type of DPDK process instance.
+
+=item B<FilePrefix> I<File>
+
+The prefix text used for hugepage filenames. The filename will be set to
+/var/run/.<prefix>_config where prefix is what is passed in by the user.
+
+=back
+
+=head3 The Event block
+
+The B<Event> 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<SendEventOnUpdate> I<true|false>
+
+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<EnabledPortMask> I<Mask>
+
+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<PortName> I<Name>
+
+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<SendNotification> I<true|false>
+
+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<SendEventOnUpdate> I<true|false>
+
+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<LCoreMask> I<Mask>
+
+An hexadecimal bit mask of the logical cores to monitor keep alive state.
+
+=item B<KeepAliveShmName> I<Name>
+
+Shared memory name identifier that is used by secondary process to monitor
+the keep alive cores state.
+
+=item B<SendNotification> I<true|false>
+
+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<dpdkstat>
The I<dpdkstat plugin> collects information about DPDK interfaces using the
FilePrefix "rte"
SocketMemory "1024"
</EAL>
+ SharedMemObj "dpdk_collectd_stats_0"
EnabledPortMask 0xffff
PortName "interface1"
PortName "interface2"
=back
-=over 4
+=over 3
+
+=item B<SharedMemObj> I<Mask>
+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<EnabledPortMask> I<Mask>
Monitor events are hardware dependant. Monitoring capabilities are detected on
plugin initialization and only supported events are monitored.
+B<Note:> I<intel_rdt> 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<contrib/systemd.collectd.service> file for more details.
+
B<Synopsis:>
<Plugin "intel_rdt">
Add a UPS to collect data from. The format is identical to the one accepted by
L<upsc(8)>.
+=item B<ForceSSL> B<true>|B<false>
+
+Stops connections from falling back to unsecured if an SSL connection
+cannot be established. Defaults to false if undeclared.
+
+=item B<VerifyPeer> I<true>|I<false>
+
+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<CAPath> 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<ln -s some.crt ./$(openssl x509 -hash -noout -in some.crt).0>
+
+Alternatively, the package openssl-perl provides a command C<c_rehash> that will
+generate links like the one described above for ALL certs in a given folder.
+Example usage:
+C<c_rehash /path/to/certs/folder>
+
=back
=head2 Plugin C<olsrd>
Socket "/var/run/openvswitch/db.sock"
Interfaces "br0" "veth0"
SendNotification false
+ DispatchValues true
</Plugin>
The plugin provides the following configuration options:
If set to true, OVS link notifications (interface status and OVS DB connection
terminate) are sent to collectd. Default value is false.
+=item B<DispatchValues> I<true|false>
+
+Dispatch the OVS DB interface link status value with configured plugin interval.
+Defaults to true. Please note, if B<SendNotification> and B<DispatchValues>
+options are false, no OVS information will be provided by the plugin.
+
=back
B<Note:> By default, the global interval setting is used within which to
and the sensible setting is a multiple of the B<ReadThreads> value.
If you are not sure, just use the default setting.
+=item B<ExtraStats> B<string>
+
+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<disk> report extra statistics like number of flush operations and total
+service time for read, write and flush operations.
+B<pcpu> report the physical user/system cpu time consumed by the hypervisor, per-vm.
+
=back
=head2 Plugin C<vmem>
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()));
*/
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);
}
#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) /* {{{ */
* 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 */
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));
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) /* {{{ */
{
/* 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);
/* TODO: Rename this function. */
void plugin_read_all(void) {
- if (record_statistics) {
- plugin_update_internal_statistics();
- }
uc_check_timeout();
return;
--- /dev/null
+/*
+ * 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 <maryam.tahhan@intel.com>
+ * Harry van Haaren <harry.van.haaren@intel.com>
+ * Serhiy Pshyk <serhiyx.pshyk@intel.com>
+ * Kim-Marie Jones <kim-marie.jones@intel.com>
+ * Krzysztof Matczak <krzysztofx@intel.com>
+ */
+
+#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 <rte_config.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_keepalive.h>
+
+#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);
+}
#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;
}
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;
}
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)
}
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;
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);
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,
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 */
} 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 */
} 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 {
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;
}
static int dpdk_stats_init(void) {
DPDK_STATS_TRACE();
-
int ret = 0;
ret = dpdk_stats_preinit();
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;
}
#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;
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)
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;
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();
}
}
+exit:
return (0);
}
static int rdt_init(void) {
int ret;
+ if(g_state == CONFIGURATION_ERROR)
+ return (-1);
+
ret = rdt_preinit();
if (ret != 0)
return ret;
#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
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;
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);
#include "common.h"
#include "plugin.h"
-#define DEFAULT_LOGFILE LOCALSTATEDIR "/log/collectd.log"
-
#if COLLECT_DEBUG
static int log_level = LOG_DEBUG;
#else
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)
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)
#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 */
};
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*/
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,
.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++) {
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);
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,
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) {
/* 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 */
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) {
/* 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))) {
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;
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);
}
}
}
/* 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);
}
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);
}
memset(buf, 0, sizeof(buf));
}
/* parsing definitely finished */
- return 0;
+ return (0);
}
static void poll_worker_cleanup(void *arg) {
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) {
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;
}
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));
}
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) {
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) {
* 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);
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));
if ((status < 0) || (((size_t)status) >= buf_len))
return (ENOMEM);
+ while((c = strchr(buf, '#')) || (c = strchr(buf, '+'))) {
+ *c = '_';
+ }
+
return (0);
} /* int format_topic */
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) {
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 */
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;
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
ups->upsname, upscli_strerror(ups->conn));
upscli_disconnect(ups->conn);
sfree(ups->conn);
+#ifdef WITH_UPSCLIENT_27
+ upscli_cleanup();
+#endif
return (-1);
}
free_nut_ups_t(this);
this = next;
}
+#ifdef WITH_UPSCLIENT_27
+ upscli_cleanup();
+#endif
return (0);
} /* int nut_shutdown */
.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.
*/
* 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) {
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);
}
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);
}
#include <atasmart.h>
#include <libudev.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/capability.h>
+#endif
+
static const char *config_keys[] = {"Disk", "IgnoreSelected", "IgnoreSleepMode",
"UseSerial"};
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 */
#include <rte_config.h>
#include <rte_eal.h>
+#include <rte_ethdev.h>
#include "common.h"
#include "utils_dpdk.h"
}
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;
+}
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. */
#include <regex.h>
#define UTILS_MATCH_FLAGS_EXCLUDE_REGEX 0x02
+#define UTILS_MATCH_FLAGS_REGEX 0x04
struct cu_match_s {
regex_t regex;
sfree(obj);
return (NULL);
}
+ obj->flags |= UTILS_MATCH_FLAGS_REGEX;
if (excluderegex && strcmp(excluderegex, "") != 0) {
status = regcomp(&obj->excluderegex, excluderegex, REG_EXTENDED);
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);
/* 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",
"PluginInstanceFormat",
"Instances",
+ "ExtraStats",
NULL};
#define NR_CONFIG_KEYS ((sizeof config_keys / sizeof config_keys[0]) - 1)
/* 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;
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 { \
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;
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);
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)
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;
}
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;
/* 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.",
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");
/* 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. */
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) {
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;
#include "utils_threshold.h"
#include "write_riemann_threshold.h"
-#include <ltdl.h>
-
/*
* Threshold management
* ====================
#!/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'`"