Merge pull request #502 from rtkmhart/write_graphite_issue_430
authorPierre-Yves Ritschard <pyr@spootnik.org>
Fri, 20 Dec 2013 23:51:35 +0000 (15:51 -0800)
committerPierre-Yves Ritschard <pyr@spootnik.org>
Fri, 20 Dec 2013 23:51:35 +0000 (15:51 -0800)
Fix issue #430 where write_graphite fails to reconnect

14 files changed:
.gitignore
README
configure.in
contrib/collection3/etc/collection.conf
src/collectd-snmp.pod
src/collectd.conf.in
src/collectd.conf.pod
src/cpu.c
src/libcollectdclient/collectd/network.h
src/libcollectdclient/network.c
src/load.c
src/netlink.c
src/snmp.c
src/write_riemann.c

index 7c7c848..e1120d3 100644 (file)
@@ -38,7 +38,9 @@ src/collectdctl
 src/collectdmon
 src/*.1
 src/*.5
+src/.pod2man.tmp.*
 src/libcollectdclient/collectd/lcc_features.h
+src/utils_vl_lookup_test
 
 # patch stuff
 *.rej
@@ -62,6 +64,7 @@ bindings/.perl-directory-stamp
 bindings/perl/Collectd/pm_to_blib
 bindings/perl/blib/
 bindings/perl/pm_to_blib
+bindings/buildperl
 
 # java stuff
 bindings/java/java-build-stamp
diff --git a/README b/README
index c0d7036..fa88f38 100644 (file)
--- a/README
+++ b/README
@@ -565,7 +565,7 @@ Prerequisites
 
   * A POSIX-threads (pthread) implementation.
     Since gathering some statistics is slow (network connections, slow devices,
-    etc) the collectd is parallelized. The POSIX threads interface is being
+    etc) collectd is parallelized. The POSIX threads interface is being
     used and should be found in various implementations for hopefully all
     platforms.
 
index 153bac4..c4d9558 100644 (file)
@@ -2662,6 +2662,15 @@ return (retval);
 fi
 if test "x$with_libmnl" = "xyes"
 then
+       AC_CHECK_MEMBERS([struct rtnl_link_stats64.tx_window_errors],
+       [AC_DEFINE(HAVE_RTNL_LINK_STATS64, 1, [Define if struct rtnl_link_stats64 exists and is usable.])],
+       [],
+       [
+       #include <linux/if_link.h>
+       ])
+fi
+if test "x$with_libmnl" = "xyes"
+then
        AC_CHECK_LIB(mnl, mnl_nlmsg_get_payload,
                     [with_libmnl="yes"],
                     [with_libmnl="no (symbol 'mnl_nlmsg_get_payload' not found)"],
index 5d1024f..5fe4313 100644 (file)
@@ -3,7 +3,7 @@ GraphWidth 400
 #UnixSockAddr "/var/run/collectd-unixsock"
 <Type apache_bytes>
   DataSources value
-  DSName "count Bytes/s"
+  DSName "value Bytes/s"
   RRDTitle "Apache Traffic"
   RRDVerticalLabel "Bytes/s"
   RRDFormat "%5.1lf%s"
@@ -11,7 +11,7 @@ GraphWidth 400
 </Type>
 <Type apache_requests>
   DataSources value
-  DSName "count Requests/s"
+  DSName "value Requests/s"
   RRDTitle "Apache Traffic"
   RRDVerticalLabel "Requests/s"
   RRDFormat "%5.2lf"
@@ -246,14 +246,14 @@ GraphWidth 400
 </Type>
 <Type conntrack>
   DataSources value
-  DSName conntrack Conntrack count
+  DSName value Conntrack count
   RRDTitle "nf_conntrack connections on {hostname}"
   RRDVerticalLabel "Count"
   RRDFormat "%4.0lf"
 </Type>
 <Type entropy>
   DataSources value
-  DSName entropy Entropy bits
+  DSName value Entropy bits
   RRDTitle "Available entropy on {hostname}"
   RRDVerticalLabel "Bits"
   RRDFormat "%4.0lf"
@@ -268,7 +268,7 @@ GraphWidth 400
 </Type>
 <Type frequency>
   DataSources value
-  DSName frequency Frequency
+  DSName value Frequency
   RRDTitle "Frequency ({type_instance})"
   RRDVerticalLabel "Hertz"
   RRDFormat "%4.1lfHz"
@@ -543,7 +543,7 @@ GraphWidth 400
 </Type>
 <Type percent>
   DataSources value
-  DSName percent Percent
+  DSName value Percent
   RRDTitle "Percent ({type_instance})"
   RRDVerticalLabel "Percent"
   RRDFormat "%4.1lf%%"
@@ -551,7 +551,7 @@ GraphWidth 400
 </Type>
 <Type ping>
   DataSources value
-  DSName "ping Latency"
+  DSName "value Latency"
   RRDTitle "Network latency ({type_instance})"
   RRDVerticalLabel "Milliseconds"
   RRDFormat "%5.2lfms"
@@ -701,7 +701,7 @@ GraphWidth 400
 </Type>
 <Type users>
   DataSources value
-  DSName users Users
+  DSName value Users
   RRDTitle "Users ({type_instance}) on {hostname}"
   RRDVerticalLabel "Users"
   RRDFormat "%.1lf"
index fd7a508..db955d6 100644 (file)
@@ -43,6 +43,17 @@ collectd-snmp - Documentation of collectd's C<snmp plugin>
       Community "another_string"
       Collect "std_traffic" "hr_users"
     </Host>
+    <Host "secure.router.mydomain.org">
+      Address "192.168.0.7"
+      Version 3
+      SecurityLevel "authPriv"
+      Username "cosmo"
+      AuthProtocol "SHA"
+      AuthPassphrase "setec_astronomy"
+      PrivacyProtocol "AES"
+      PrivacyPassphrase "too_many_secrets"
+      Collect "std_traffic"
+    </Host>
     <Host "some.ups.mydomain.org">
       Address "192.168.0.3"
       Version 1
@@ -191,6 +202,18 @@ degrees Celsius. The default value is, of course, B<0.0>.
 
 This value is not applied to counter-values.
 
+=item B<Ignore> I<Value> [, I<Value> ...]
+
+The ignore values allows to ignore Instances based on their name and the patterns
+specified by the various values you've entered. The match is a glob-type shell
+matching.
+
+=item B<InvertMatch> I<true|false(default)>
+
+The invertmatch value should be use in combination of the Ignore option.
+It changes the behaviour of the Ignore option, from a blacklist behaviour
+when InvertMatch is set to false, to a whitelist when specified to true.
+
 =back
 
 =head2 The Host block
@@ -207,14 +230,41 @@ stored by collectd.
 
 Set the address to connect to.
 
-=item B<Version> B<1>|B<2>
+=item B<Version> B<1>|B<2>|B<3>
 
 Set the SNMP version to use. When giving B<2> version C<2c> is actually used.
-Version 3 is not supported by this plugin.
 
 =item B<Community> I<Community>
 
-Pass I<Community> to the host.
+Pass I<Community> to the host. (Ignored for SNMPv3).
+
+=item B<Username> I<Username>
+
+Sets the I<Username> to use for SNMPv3 security.
+
+=item B<SecurityLevel> I<authPriv>|I<authNoPriv>|I<noAuthNoPriv>
+
+Selects the security level for SNMPv3 security.
+
+=item B<Context> I<Context>
+
+Sets the I<Context> for SNMPv3 security.
+
+=item B<AuthProtocol> I<MD5>|I<SHA>
+
+Selects the authentication protocol for SNMPv3 security.
+
+=item B<AuthPassphrase> I<Passphrase>
+
+Sets the authentication passphrase for SNMPv3 security. 
+
+=item B<PrivacyProtocol> I<AES>|I<DES>
+
+Selects the privacy (encryption) protocol for SNMPv3 security.
+
+=item B<PrivacyPassphrase> I<Passphrase>
+
+Sets the privacy (encryption) passphrase for SNMPv3 security. 
 
 =item B<Collect> I<Data> [I<Data> ...]
 
@@ -241,8 +291,9 @@ L<snmpgetnext(1)>,
 L<variables(5)>,
 L<unix(7)>
 
-=head1 AUTHOR
+=head1 AUTHORS
 
 Florian Forster E<lt>octo@verplant.orgE<gt>
+Michael Pilat E<lt>mike@mikepilat.comE<gt>
 
 =cut
index d4d5a20..cc8f556 100644 (file)
 #      InterfaceFormat name
 #</Plugin>
 
+#<Plugin load>
+#        ReportRelative true
+#</Plugin>
+
 #<Plugin lpar>
 #      CpuPoolStats   false
 #      ReportBySerial false
 #              AlwaysAppendDS false
 #      </Node>
 #      Tag "foobar"
+#       Attribute "foo" "bar"
 #</Plugin>
 
 ##############################################################################
index 691a749..e6b6afd 100644 (file)
@@ -2199,6 +2199,25 @@ interface path might change between reboots of a guest or across migrations.
 
 =back
 
++=head2 Plugin C<load>
+
+The I<Load plugin> collects the system load. These numbers give a rough overview
+over the utilization of a machine. The system load is defined as the number of
+runnable tasks in the run-queue and is provided by many operating systems as a
+one, five or fifteen minute average.
+
+The following configuration options are available:
+
+=over 4
+
+=item B<ReportRelative> B<false>|B<true>
+
+When enabled, system load divided by number of available CPU cores is reported
+for intervals 1 min, 5 min and 15 min. Defaults to false.
+
+=back
+
+
 =head2 Plugin C<logfile>
 
 =over 4
@@ -6288,6 +6307,7 @@ Synopsis:
      TTLFactor 2.0
    </Node>
    Tag "foobar"
+   Attribute "foo" "bar"
  </Plugin>
 
 The following options are understood by the I<write_riemann plugin>:
@@ -6348,6 +6368,11 @@ default value.
 Add the given string as an additional tag to the metric being sent to
 I<Riemann>.
 
+=item B<Attribute> I<String> I<String>
+
+Consider the two given strings to be the key and value of an additional
+attribute for each metric being sent out to I<Riemann>.
+
 =back
 
 =head1 THRESHOLD CONFIGURATION
index 2247d5f..f1aa4ab 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -268,6 +268,7 @@ static int cpu_read (void)
        kern_return_t status;
        
 #if PROCESSOR_CPU_LOAD_INFO
+       derive_t                       cpu_active;
        processor_cpu_load_info_data_t cpu_info;
        mach_msg_type_number_t         cpu_info_len;
 #endif
@@ -302,6 +303,11 @@ static int cpu_read (void)
                submit (cpu, "nice", (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE]);
                submit (cpu, "system", (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM]);
                submit (cpu, "idle", (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE]);
+               cpu_active = (derive_t) (cpu_info.cpu_ticks[CPU_STATE_USER] +
+                                        cpu_info.cpu_ticks[CPU_STATE_NICE] +
+                                        cpu_info.cpu_ticks[CPU_STATE_SYSTEM]);
+               submit (cpu, "active", cpu_active);
+                                        
 #endif /* PROCESSOR_CPU_LOAD_INFO */
 #if PROCESSOR_TEMPERATURE
                /*
@@ -350,6 +356,7 @@ static int cpu_read (void)
 
 #elif defined(KERNEL_LINUX)
        int cpu;
+       derive_t cpu_active;
        derive_t user, nice, syst, idle;
        derive_t wait, intr, sitr; /* sitr == soft interrupt */
        FILE *fh;
@@ -387,6 +394,7 @@ static int cpu_read (void)
                submit (cpu, "nice", nice);
                submit (cpu, "system", syst);
                submit (cpu, "idle", idle);
+               cpu_active = user + nice + syst;
 
                if (numfields >= 8)
                {
@@ -397,10 +405,14 @@ static int cpu_read (void)
                        submit (cpu, "wait", wait);
                        submit (cpu, "interrupt", intr);
                        submit (cpu, "softirq", sitr);
+                       
+                       cpu_active += wait + intr + sitr;
 
                        if (numfields >= 9)
+                               cpu_active += (derive_t) atoll (fields[8]);
                                submit (cpu, "steal", atoll (fields[8]));
                }
+               submit (cpu, "active", cpu_active);
        }
 
        fclose (fh);
@@ -428,6 +440,7 @@ static int cpu_read (void)
                submit (ksp[cpu]->ks_instance, "system", syst);
                submit (ksp[cpu]->ks_instance, "idle", idle);
                submit (ksp[cpu]->ks_instance, "wait", wait);
+               submit (ksp[cpu]->ks_instance, "active", user + syst + wait);
        }
 /* #endif defined(HAVE_LIBKSTAT) */
 
@@ -492,6 +505,10 @@ static int cpu_read (void)
                submit (i, "system",    cpuinfo[i][CP_SYS]);
                submit (i, "idle",      cpuinfo[i][CP_IDLE]);
                submit (i, "interrupt", cpuinfo[i][CP_INTR]);
+               submit (i, "active",    cpuinfo[i][CP_USER] +
+                                       cpuinfo[i][CP_NICE] +
+                                       cpuinfo[i][CP_SYS] +
+                                       cpuinfo[i][CP_INTR]);
        }
 /* #endif CAN_USE_SYSCTL */
 #elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
@@ -516,6 +533,10 @@ static int cpu_read (void)
                submit (i, "system", cpuinfo[i][CP_SYS]);
                submit (i, "idle", cpuinfo[i][CP_IDLE]);
                submit (i, "interrupt", cpuinfo[i][CP_INTR]);
+               submit (i, "active", cpuinfo[i][CP_USER] +
+                       cpuinfo[i][CP_NICE] +
+                       cpuinfo[i][CP_SYS] +
+                       cpuinfo[i][CP_INTR]);
        }
 /* #endif HAVE_SYSCTL_KERN_CP_TIMES */
 #elif defined(HAVE_SYSCTLBYNAME)
@@ -537,6 +558,10 @@ static int cpu_read (void)
        submit (0, "system", cpuinfo[CP_SYS]);
        submit (0, "idle", cpuinfo[CP_IDLE]);
        submit (0, "interrupt", cpuinfo[CP_INTR]);
+       submit (0, "active", cpuinfo[CP_USER] +
+               cpuinfo[CP_NICE] +
+               cpuinfo[CP_SYS] +
+               cpuinfo[CP_INTR]);
 /* #endif HAVE_SYSCTLBYNAME */
 
 #elif defined(HAVE_LIBSTATGRAB)
@@ -555,6 +580,12 @@ static int cpu_read (void)
        submit (0, "system", (derive_t) cs->kernel);
        submit (0, "user",   (derive_t) cs->user);
        submit (0, "wait",   (derive_t) cs->iowait);
+       submit (0, "active", (derive_t) cs->nice + 
+               cs->swap +
+               cs->kernel +
+               cs->user +
+               cs->iowait +
+               cs->nice);
 /* #endif HAVE_LIBSTATGRAB */
 
 #elif defined(HAVE_PERFSTAT)
@@ -593,6 +624,9 @@ static int cpu_read (void)
                submit (i, "system", (derive_t) perfcpu[i].sys);
                submit (i, "user",   (derive_t) perfcpu[i].user);
                submit (i, "wait",   (derive_t) perfcpu[i].wait);
+               submit (i, "active", (derive_t) perfcpu[i].sys +
+                       perfcpu[i].user +
+                       perfcpu[i].wait);
        }
 #endif /* HAVE_PERFSTAT */
 
index 3962666..049f7f0 100644 (file)
@@ -65,6 +65,7 @@ int lcc_server_destroy (lcc_network_t *net, lcc_server_t *srv);
 
 /* Configure servers */
 int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl);
+int lcc_server_set_interface (lcc_server_t *srv, char const *interface);
 int lcc_server_set_security_level (lcc_server_t *srv,
     lcc_security_level_t level,
     const char *username, const char *password);
index 6b6450c..ddb3b5b 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/libcollectdclient/network.c
- * Copyright (C) 2005-2012  Florian octo Forster
+ * Copyright (C) 2005-2013  Florian Forster
+ * Copyright (C) 2010       Max Henkel
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -21,7 +22,8 @@
  * DEALINGS IN THE SOFTWARE.
  *
  * Authors:
- *   Florian octo Forster <octo at collectd.org>
+ *   Florian Forster <octo at collectd.org>
+ *   Max Henkel <henkel at gmx.at>
  **/
 
 #include "collectd.h"
 # include <netinet/in.h>
 #endif
 
+#if HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+
 #include "collectd/network.h"
 #include "collectd/network_buffer.h"
 
@@ -379,6 +385,81 @@ int lcc_server_set_ttl (lcc_server_t *srv, uint8_t ttl) /* {{{ */
   return (0);
 } /* }}} int lcc_server_set_ttl */
 
+int lcc_server_set_interface (lcc_server_t *srv, char const *interface) /* {{{ */
+{
+  int if_index;
+  int status;
+
+  if ((srv == NULL) || (interface == NULL))
+    return (EINVAL);
+
+  if_index = if_nametoindex (interface);
+  if (if_index == 0)
+    return (ENOENT);
+
+  /* IPv4 multicast */
+  if (srv->sa->sa_family == AF_INET)
+  {
+    struct sockaddr_in *addr = (struct sockaddr_in *) srv->sa;
+
+    if (IN_MULTICAST (ntohl (addr->sin_addr.s_addr)))
+    {
+#if HAVE_STRUCT_IP_MREQN_IMR_IFINDEX
+      /* If possible, use the "ip_mreqn" structure which has
+       * an "interface index" member. Using the interface
+       * index is preferred here, because of its similarity
+       * to the way IPv6 handles this. Unfortunately, it
+       * appears not to be portable. */
+      struct ip_mreqn mreq;
+
+      memset (&mreq, 0, sizeof (mreq));
+      mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
+      mreq.imr_address.s_addr = ntohl (INADDR_ANY);
+      mreq.imr_ifindex = if_index;
+#else
+      struct ip_mreq mreq;
+
+      memset (&mreq, 0, sizeof (mreq));
+      mreq.imr_multiaddr.s_addr = addr->sin_addr.s_addr;
+      mreq.imr_interface.s_addr = ntohl (INADDR_ANY);
+#endif
+
+      status = setsockopt (srv->fd, IPPROTO_IP, IP_MULTICAST_IF,
+          &mreq, sizeof (mreq));
+      if (status != 0)
+        return (status);
+
+      return (0);
+    }
+  }
+
+  /* IPv6 multicast */
+  if (srv->sa->sa_family == AF_INET6)
+  {
+    struct sockaddr_in6 *addr = (struct sockaddr_in6 *) srv->sa;
+
+    if (IN6_IS_ADDR_MULTICAST (&addr->sin6_addr))
+    {
+      status = setsockopt (srv->fd, IPPROTO_IPV6, IPV6_MULTICAST_IF,
+          &if_index, sizeof (if_index));
+      if (status != 0)
+        return (status);
+
+      return (0);
+    }
+  }
+
+  /* else: Not a multicast interface. */
+#if defined(SO_BINDTODEVICE)
+  status = setsockopt (srv->fd, SOL_SOCKET, SO_BINDTODEVICE,
+      interface, strlen (interface) + 1);
+  if (status != 0)
+    return (-1);
+#endif
+
+  return (0);
+} /* }}} int lcc_server_set_interface */
+
 int lcc_server_set_security_level (lcc_server_t *srv, /* {{{ */
     lcc_security_level_t level,
     const char *username, const char *password)
index 0188da7..9b5dd3d 100644 (file)
@@ -2,6 +2,7 @@
  * collectd - src/load.c
  * Copyright (C) 2005-2008  Florian octo Forster
  * Copyright (C) 2009       Manuel Sanmartin
+ * Copyright (C) 2013       Vedran Bartonicek
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
@@ -19,6 +20,7 @@
  * Authors:
  *   Florian octo Forster <octo at verplant.org>
  *   Manuel Sanmartin
+ *   Vedran Bartonicek <vbartoni at gmail.com>
  **/
 
 #define _BSD_SOURCE
@@ -27,6 +29,8 @@
 #include "common.h"
 #include "plugin.h"
 
+#include <unistd.h>
+
 #ifdef HAVE_SYS_LOADAVG_H
 #include <sys/loadavg.h>
 #endif
 # include <libperfstat.h>
 #endif /* HAVE_PERFSTAT */
 
+static _Bool report_relative_load = 0;
+
+static const char *config_keys[] =
+{
+       "ReportRelative"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+
+static int load_config (const char *key, const char *value)
+{
+       if (strcasecmp (key, "ReportRelative") == 0)
+#ifdef _SC_NPROCESSORS_ONLN
+               report_relative_load = IS_TRUE (value) ? 1 : 0;
+#else
+                WARNING ("load plugin: The \"ReportRelative\" configuration "
+                         "is not available, because I can't determine the "
+                         "number of CPUS on this system. Sorry.");
+#endif
+       return (-1);
+
+}
 static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
 {
        value_t values[3];
        value_list_t vl = VALUE_LIST_INIT;
+        int cores = 0;
+        char errbuf[1024];
+
+#ifdef  _SC_NPROCESSORS_ONLN
+        if (report_relative_load) {
+                if ((cores = sysconf(_SC_NPROCESSORS_ONLN)) < 1) {
+                       WARNING ("load: sysconf failed : %s",
+                                sstrerror (errno, errbuf, sizeof (errbuf)));
+               }
+       }
+#endif
+       if (cores > 0) {
+               snum /= cores;
+               mnum /= cores;
+               lnum /= cores;
+       }
 
        values[0].gauge = snum;
        values[1].gauge = mnum;
@@ -60,10 +101,16 @@ static void load_submit (gauge_t snum, gauge_t mnum, gauge_t lnum)
 
        vl.values = values;
        vl.values_len = STATIC_ARRAY_SIZE (values);
+
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "load", sizeof (vl.plugin));
        sstrncpy (vl.type, "load", sizeof (vl.type));
 
+       if (cores > 0) {
+               sstrncpy(vl.type_instance, "relative",
+                        sizeof (vl.type_instance));
+       }
+
        plugin_dispatch_values (&vl);
 }
 
@@ -73,17 +120,17 @@ static int load_read (void)
        double load[3];
 
        if (getloadavg (load, 3) == 3)
-               load_submit (load[LOADAVG_1MIN], load[LOADAVG_5MIN], load[LOADAVG_15MIN]);
-       else
-       {
-               char errbuf[1024];
-               WARNING ("load: getloadavg failed: %s",
-                               sstrerror (errno, errbuf, sizeof (errbuf)));
+                load_submit (load[LOADAVG_1MIN], load[LOADAVG_5MIN], load[LOADAVG_15MIN]);
+        else
+        {
+                char errbuf[1024];
+                WARNING ("load: getloadavg failed: %s",
+                         sstrerror (errno, errbuf, sizeof (errbuf)));
        }
 /* #endif HAVE_GETLOADAVG */
 
 #elif defined(KERNEL_LINUX)
-       gauge_t snum, mnum, lnum;
+        gauge_t snum, mnum, lnum;
        FILE *loadavg;
        char buffer[16];
 
@@ -123,11 +170,11 @@ static int load_read (void)
        mnum = atof (fields[1]);
        lnum = atof (fields[2]);
 
-       load_submit (snum, mnum, lnum);
+        load_submit(snum, mnum, lnum);
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBSTATGRAB
-       gauge_t snum, mnum, lnum;
+        gauge_t snum, mnum, lnum;
        sg_load_stats *ls;
 
        if ((ls = sg_get_load_stats ()) == NULL)
@@ -136,12 +183,11 @@ static int load_read (void)
        snum = ls->min1;
        mnum = ls->min5;
        lnum = ls->min15;
-
-       load_submit (snum, mnum, lnum);
+        load_submit(snum, mnum, lnum);
 /* #endif HAVE_LIBSTATGRAB */
 
 #elif HAVE_PERFSTAT
-       gauge_t snum, mnum, lnum;
+        gauge_t snum, mnum, lnum;
        perfstat_cpu_total_t cputotal;
 
        if (perfstat_cpu_total(NULL,  &cputotal, sizeof(perfstat_cpu_total_t), 1) < 0)
@@ -155,8 +201,7 @@ static int load_read (void)
        snum = (float)cputotal.loadavg[0]/(float)(1<<SBITS);
        mnum = (float)cputotal.loadavg[1]/(float)(1<<SBITS);
        lnum = (float)cputotal.loadavg[2]/(float)(1<<SBITS);
-
-       load_submit (snum, mnum, lnum);
+        load_submit(snum, mnum, lnum);
 /* #endif HAVE_PERFSTAT */
 
 #else
@@ -168,5 +213,6 @@ static int load_read (void)
 
 void module_register (void)
 {
+       plugin_register_config ("load", load_config, config_keys, config_keys_num);
        plugin_register_read ("load", load_read);
 } /* void module_register */
index 422dc8c..5e670d4 100644 (file)
 
 #include <libmnl/libmnl.h>
 
+struct ir_link_stats_storage_s {
+
+  uint64_t rx_packets;
+  uint64_t tx_packets;
+  uint64_t rx_bytes;
+  uint64_t tx_bytes;
+  uint64_t rx_errors;
+  uint64_t tx_errors;
+
+  uint64_t rx_dropped;
+  uint64_t tx_dropped;
+  uint64_t multicast;
+  uint64_t collisions;
+
+  uint64_t rx_length_errors;
+  uint64_t rx_over_errors;
+  uint64_t rx_crc_errors;
+  uint64_t rx_frame_errors;
+  uint64_t rx_fifo_errors;
+  uint64_t rx_missed_errors;
+
+  uint64_t tx_aborted_errors;
+  uint64_t tx_carrier_errors;
+  uint64_t tx_fifo_errors;
+  uint64_t tx_heartbeat_errors;
+  uint64_t tx_window_errors;
+};
+
+union ir_link_stats_u {
+  struct rtnl_link_stats *stats32;
+#ifdef HAVE_RTNL_LINK_STATS64
+  struct rtnl_link_stats64 *stats64;
+#endif
+};
+
 typedef struct ir_ignorelist_s
 {
   char *device;
@@ -235,7 +270,7 @@ static int update_iflist (struct ifinfomsg *msg, const char *dev)
 } /* int update_iflist */
 
 static void check_ignorelist_and_submit (const char *dev,
-    struct rtnl_link_stats *stats)
+    struct ir_link_stats_storage_s *stats)
 {
 
   if (check_ignorelist (dev, "interface", NULL) == 0)
@@ -275,13 +310,61 @@ static void check_ignorelist_and_submit (const char *dev,
 
 } /* void check_ignorelist_and_submit */
 
+#define COPY_RTNL_LINK_VALUE (dst_stats, src_stats, value_name) \
+  (dst_stats)->value_name = (src_stats)->value_name
+
+#define COPY_RTNL_LINK_STATS (dst_stats, src_stats) \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_packets); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_packets); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_bytes); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_bytes); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_dropped); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_dropped); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, multicast); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, collisions); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_length_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_over_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_crc_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_frame_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_fifo_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, rx_missed_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_aborted_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_carrier_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_fifo_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_heartbeat_errors); \
+  COPY_RTNL_LINK_VALUE (dst_stats, src_stats, tx_window_errors)
+
+#ifdef HAVE_RTNL_LINK_STATS64
+static void check_ignorelist_and_submit64 (const char *dev,
+    struct rtnl_link_stats64 *stats)
+{
+  struct ir_link_stats_storage_s s;
+
+  COPY_RTNL_LINK_STATS (&s, stats);
+
+  check_ignorelist_and_submit (dev, &s);
+}
+#endif
+
+static void check_ignorelist_and_submit32 (const char *dev,
+    struct rtnl_link_stats *stats)
+{
+  struct ir_link_stats_storage_s s;
+
+  COPY_RTNL_LINK_STATS(&s, stats);
+
+  check_ignorelist_and_submit (dev, &s);
+}
+
 static int link_filter_cb (const struct nlmsghdr *nlh,
     void *args __attribute__((unused)))
 {
   struct ifinfomsg *ifm = mnl_nlmsg_get_payload (nlh);
   struct nlattr *attr;
-  struct rtnl_link_stats *stats = NULL;
   const char *dev = NULL;
+  union ir_link_stats_u stats;
 
   if (nlh->nlmsg_type != RTM_NEWLINK)
   {
@@ -313,30 +396,44 @@ static int link_filter_cb (const struct nlmsghdr *nlh,
     ERROR ("netlink plugin: link_filter_cb: dev == NULL");
     return MNL_CB_ERROR;
   }
+#ifdef HAVE_RTNL_LINK_STATS64
+  mnl_attr_for_each (attr, nlh, sizeof (*ifm))
+  {
+    if (mnl_attr_get_type (attr) != IFLA_STATS64)
+      continue;
+
+    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats64)) < 0)
+    {
+      ERROR ("netlink plugin: link_filter_cb: IFLA_STATS64 mnl_attr_validate2 failed.");
+      return MNL_CB_ERROR;
+    }
+    stats.stats64 = mnl_attr_get_payload (attr);
+
+    check_ignorelist_and_submit64 (dev, stats.stats64);
 
+    return MNL_CB_OK;
+  }
+#endif
   mnl_attr_for_each (attr, nlh, sizeof (*ifm))
   {
     if (mnl_attr_get_type (attr) != IFLA_STATS)
       continue;
 
-    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats)) < 0)
+    if (mnl_attr_validate2 (attr, MNL_TYPE_UNSPEC, sizeof (*stats.stats32)) < 0)
     {
       ERROR ("netlink plugin: link_filter_cb: IFLA_STATS mnl_attr_validate2 failed.");
       return MNL_CB_ERROR;
     }
-    stats = mnl_attr_get_payload (attr);
+    stats.stats32 = mnl_attr_get_payload (attr);
 
-    check_ignorelist_and_submit (dev, stats);
-    break;
-  }
+    check_ignorelist_and_submit32 (dev, stats.stats32);
 
-  if (stats == NULL)
-  {
-    DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev);
     return MNL_CB_OK;
   }
 
+  DEBUG ("netlink plugin: link_filter: No statistics for interface %s.", dev);
   return MNL_CB_OK;
+
 } /* int link_filter_cb */
 
 #if HAVE_TCA_STATS2
index ad81c89..2bb7c2a 100644 (file)
@@ -29,6 +29,8 @@
 #include <net-snmp/net-snmp-config.h>
 #include <net-snmp/net-snmp-includes.h>
 
+#include <fnmatch.h>
+
 /*
  * Private data structes
  */
@@ -50,7 +52,7 @@ struct data_definition_s
 {
   char *name; /* used to reference this from the `Collect' option */
   char *type; /* used to find the data_set */
-  int is_table;
+  _Bool is_table;
   instance_t instance;
   char *instance_prefix;
   oid_t *values;
@@ -58,6 +60,9 @@ struct data_definition_s
   double scale;
   double shift;
   struct data_definition_s *next;
+  char **ignores;
+  size_t ignores_len;
+  int invert_match;
 };
 typedef struct data_definition_s data_definition_t;
 
@@ -65,8 +70,22 @@ struct host_definition_s
 {
   char *name;
   char *address;
-  char *community;
   int version;
+
+  /* snmpv1/2 options */
+  char *community;
+
+  /* snmpv3 security options */
+  char *username;
+  oid *auth_protocol;
+  size_t auth_protocol_len;
+  char *auth_passphrase;
+  oid *priv_protocol;
+  size_t priv_protocol_len;
+  char *priv_passphrase;
+  int security_level;
+  char *context;
+
   void *sess_handle;
   c_complain_t complaint;
   cdtime_t interval;
@@ -183,6 +202,10 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */
   sfree (hd->name);
   sfree (hd->address);
   sfree (hd->community);
+  sfree (hd->username);
+  sfree (hd->auth_passphrase);
+  sfree (hd->priv_passphrase);
+  sfree (hd->context);
   sfree (hd->data_list);
 
   sfree (hd);
@@ -197,16 +220,15 @@ static void csnmp_host_definition_destroy (void *arg) /* {{{ */
  *  csnmp_config
  *  +-> call_snmp_init_once
  *  +-> csnmp_config_add_data
- *  !   +-> csnmp_config_add_data_type
- *  !   +-> csnmp_config_add_data_table
  *  !   +-> csnmp_config_add_data_instance
  *  !   +-> csnmp_config_add_data_instance_prefix
  *  !   +-> csnmp_config_add_data_values
  *  +-> csnmp_config_add_host
- *      +-> csnmp_config_add_host_address
- *      +-> csnmp_config_add_host_community
  *      +-> csnmp_config_add_host_version
  *      +-> csnmp_config_add_host_collect
+ *      +-> csnmp_config_add_host_auth_protocol
+ *      +-> csnmp_config_add_host_priv_protocol
+ *      +-> csnmp_config_add_host_security_level
  */
 static void call_snmp_init_once (void)
 {
@@ -217,60 +239,31 @@ static void call_snmp_init_once (void)
   have_init = 1;
 } /* void call_snmp_init_once */
 
-static int csnmp_config_add_data_type (data_definition_t *dd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: `Type' needs exactly one string argument.");
-    return (-1);
-  }
-
-  sfree (dd->type);
-  dd->type = strdup (ci->values[0].value.string);
-  if (dd->type == NULL)
-    return (-1);
-
-  return (0);
-} /* int csnmp_config_add_data_type */
-
-static int csnmp_config_add_data_table (data_definition_t *dd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
-  {
-    WARNING ("snmp plugin: `Table' needs exactly one boolean argument.");
-    return (-1);
-  }
-
-  dd->is_table = ci->values[0].value.boolean ? 1 : 0;
-
-  return (0);
-} /* int csnmp_config_add_data_table */
-
 static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t *ci)
 {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: `Instance' needs exactly one string argument.");
-    return (-1);
-  }
+  char buffer[DATA_MAX_NAME_LEN];
+  int status;
+
+  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
 
   if (dd->is_table)
   {
     /* Instance is an OID */
     dd->instance.oid.oid_len = MAX_OID_LEN;
 
-    if (!read_objid (ci->values[0].value.string,
+    if (!read_objid (buffer,
           dd->instance.oid.oid, &dd->instance.oid.oid_len))
     {
-      ERROR ("snmp plugin: read_objid (%s) failed.",
-          ci->values[0].value.string);
+      ERROR ("snmp plugin: read_objid (%s) failed.", buffer);
       return (-1);
     }
   }
   else
   {
     /* Instance is a simple string */
-    sstrncpy (dd->instance.string, ci->values[0].value.string,
+    sstrncpy (dd->instance.string, buffer,
         sizeof (dd->instance.string));
   }
 
@@ -280,11 +273,7 @@ static int csnmp_config_add_data_instance (data_definition_t *dd, oconfig_item_t
 static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
     oconfig_item_t *ci)
 {
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: `InstancePrefix' needs exactly one string argument.");
-    return (-1);
-  }
+  int status;
 
   if (!dd->is_table)
   {
@@ -293,12 +282,8 @@ static int csnmp_config_add_data_instance_prefix (data_definition_t *dd,
     return (-1);
   }
 
-  sfree (dd->instance_prefix);
-  dd->instance_prefix = strdup (ci->values[0].value.string);
-  if (dd->instance_prefix == NULL)
-    return (-1);
-
-  return (0);
+  status = cf_util_get_string(ci, &dd->instance_prefix);
+  return status;
 } /* int csnmp_config_add_data_instance_prefix */
 
 static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *ci)
@@ -344,33 +329,49 @@ static int csnmp_config_add_data_values (data_definition_t *dd, oconfig_item_t *
   return (0);
 } /* int csnmp_config_add_data_instance */
 
-static int csnmp_config_add_data_shift (data_definition_t *dd, oconfig_item_t *ci)
+static int csnmp_config_add_data_blacklist(data_definition_t *dd, oconfig_item_t *ci)
 {
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  int i;
+
+  if (ci->values_num < 1)
+    return (0);
+
+  for (i = 0; i < ci->values_num; i++)
   {
-    WARNING ("snmp plugin: The `Shift' config option needs exactly one number argument.");
-    return (-1);
+    if (ci->values[i].type != OCONFIG_TYPE_STRING)
+    {
+      WARNING ("snmp plugin: `Ignore' needs only string argument.");
+      return (-1);
+    }
   }
 
-  dd->shift = ci->values[0].value.number;
+  dd->ignores_len = 0;
+  dd->ignores = NULL;
 
-  return (0);
-} /* int csnmp_config_add_data_shift */
+  for (i = 0; i < ci->values_num; ++i)
+  {
+    if (strarray_add(&(dd->ignores), &(dd->ignores_len), ci->values[i].value.string) != 0)
+    {
+      ERROR("snmp plugin: Can't allocate memory");
+      strarray_free(dd->ignores, dd->ignores_len);
+      return (ENOMEM); 
+    }
+  }
+  return 0;
+} /* int csnmp_config_add_data_blacklist */
 
-static int csnmp_config_add_data_scale (data_definition_t *dd, oconfig_item_t *ci)
+static int csnmp_config_add_data_blacklist_match_inverted(data_definition_t *dd, oconfig_item_t *ci)
 {
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_NUMBER))
+  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_BOOLEAN))
   {
-    WARNING ("snmp plugin: The `Scale' config option needs exactly one number argument.");
+    WARNING ("snmp plugin: `InvertMatch' needs exactly one boolean argument.");
     return (-1);
   }
 
-  dd->scale = ci->values[0].value.number;
+  dd->invert_match = ci->values[0].value.boolean ? 1 : 0;
 
   return (0);
-} /* int csnmp_config_add_data_scale */
+} /* int csnmp_config_add_data_blacklist_match_inverted */
 
 static int csnmp_config_add_data (oconfig_item_t *ci)
 {
@@ -378,24 +379,18 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
   int status = 0;
   int i;
 
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: The `Data' config option needs exactly one string argument.");
-    return (-1);
-  }
-
   dd = (data_definition_t *) malloc (sizeof (data_definition_t));
   if (dd == NULL)
     return (-1);
   memset (dd, '\0', sizeof (data_definition_t));
 
-  dd->name = strdup (ci->values[0].value.string);
-  if (dd->name == NULL)
+  status = cf_util_get_string(ci, &dd->name);
+  if (status != 0)
   {
     free (dd);
     return (-1);
   }
+
   dd->scale = 1.0;
   dd->shift = 0.0;
 
@@ -405,9 +400,9 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
     status = 0;
 
     if (strcasecmp ("Type", option->key) == 0)
-      status = csnmp_config_add_data_type (dd, option);
+      status = cf_util_get_string(option, &dd->type);
     else if (strcasecmp ("Table", option->key) == 0)
-      status = csnmp_config_add_data_table (dd, option);
+      status = cf_util_get_boolean(option, &dd->is_table);
     else if (strcasecmp ("Instance", option->key) == 0)
       status = csnmp_config_add_data_instance (dd, option);
     else if (strcasecmp ("InstancePrefix", option->key) == 0)
@@ -415,9 +410,13 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
     else if (strcasecmp ("Values", option->key) == 0)
       status = csnmp_config_add_data_values (dd, option);
     else if (strcasecmp ("Shift", option->key) == 0)
-      status = csnmp_config_add_data_shift (dd, option);
+      status = cf_util_get_double(option, &dd->shift);
     else if (strcasecmp ("Scale", option->key) == 0)
-      status = csnmp_config_add_data_scale (dd, option);
+      status = cf_util_get_double(option, &dd->scale);
+    else if (strcasecmp ("Ignore", option->key) == 0)
+      status = csnmp_config_add_data_blacklist(dd, option);
+    else if (strcasecmp ("InvertMatch", option->key) == 0)
+      status = csnmp_config_add_data_blacklist_match_inverted(dd, option);
     else
     {
       WARNING ("snmp plugin: Option `%s' not allowed here.", option->key);
@@ -451,6 +450,7 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
     sfree (dd->name);
     sfree (dd->instance_prefix);
     sfree (dd->values);
+    sfree (dd->ignores);
     sfree (dd);
     return (-1);
   }
@@ -472,50 +472,6 @@ static int csnmp_config_add_data (oconfig_item_t *ci)
   return (0);
 } /* int csnmp_config_add_data */
 
-static int csnmp_config_add_host_address (host_definition_t *hd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: The `Address' config option needs exactly one string argument.");
-    return (-1);
-  }
-
-  if (hd->address == NULL)
-    free (hd->address);
-
-  hd->address = strdup (ci->values[0].value.string);
-  if (hd->address == NULL)
-    return (-1);
-
-  DEBUG ("snmp plugin: host = %s; host->address = %s;",
-      hd->name, hd->address);
-
-  return (0);
-} /* int csnmp_config_add_host_address */
-
-static int csnmp_config_add_host_community (host_definition_t *hd, oconfig_item_t *ci)
-{
-  if ((ci->values_num != 1)
-      || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: The `Community' config option needs exactly one string argument.");
-    return (-1);
-  }
-
-  if (hd->community == NULL)
-    free (hd->community);
-
-  hd->community = strdup (ci->values[0].value.string);
-  if (hd->community == NULL)
-    return (-1);
-
-  DEBUG ("snmp plugin: host = %s; host->community = %s;",
-      hd->name, hd->community);
-
-  return (0);
-} /* int csnmp_config_add_host_community */
-
 static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t *ci)
 {
   int version;
@@ -528,9 +484,9 @@ static int csnmp_config_add_host_version (host_definition_t *hd, oconfig_item_t
   }
 
   version = (int) ci->values[0].value.number;
-  if ((version != 1) && (version != 2))
+  if ((version < 1) || (version > 3))
   {
-    WARNING ("snmp plugin: `Version' must either be `1' or `2'.");
+    WARNING ("snmp plugin: `Version' must either be `1', `2', or `3'.");
     return (-1);
   }
 
@@ -590,6 +546,92 @@ static int csnmp_config_add_host_collect (host_definition_t *host,
   return (0);
 } /* int csnmp_config_add_host_collect */
 
+static int csnmp_config_add_host_auth_protocol (host_definition_t *hd, oconfig_item_t *ci)
+{
+  char buffer[4];
+  int status;
+
+  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
+
+  if (strcasecmp("MD5", buffer) == 0) {
+    hd->auth_protocol = usmHMACMD5AuthProtocol;
+    hd->auth_protocol_len = sizeof(usmHMACMD5AuthProtocol)/sizeof(oid);
+  }
+  else if (strcasecmp("SHA", buffer) == 0) {
+    hd->auth_protocol = usmHMACSHA1AuthProtocol;
+    hd->auth_protocol_len = sizeof(usmHMACSHA1AuthProtocol)/sizeof(oid);
+  }
+  else
+  {
+    WARNING ("snmp plugin: The `AuthProtocol' config option must be `MD5' or `SHA'.");
+    return (-1);
+  }
+
+  DEBUG ("snmp plugin: host = %s; host->auth_protocol = %s;",
+      hd->name, hd->auth_protocol == usmHMACMD5AuthProtocol ? "MD5" : "SHA");
+
+  return (0);
+} /* int csnmp_config_add_host_auth_protocol */
+
+static int csnmp_config_add_host_priv_protocol (host_definition_t *hd, oconfig_item_t *ci)
+{
+  char buffer[4];
+  int status;
+
+  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
+
+  if (strcasecmp("AES", buffer) == 0)
+  {
+    hd->priv_protocol = usmAESPrivProtocol;
+    hd->priv_protocol_len = sizeof(usmAESPrivProtocol)/sizeof(oid);
+  }
+  else if (strcasecmp("DES", buffer) == 0) {
+    hd->priv_protocol = usmDESPrivProtocol;
+    hd->priv_protocol_len = sizeof(usmDESPrivProtocol)/sizeof(oid);
+  }
+  else
+  {
+    WARNING ("snmp plugin: The `PrivProtocol' config option must be `AES' or `DES'.");
+    return (-1);
+  }
+
+  DEBUG ("snmp plugin: host = %s; host->priv_protocol = %s;",
+      hd->name, hd->priv_protocol == usmAESPrivProtocol ? "AES" : "DES");
+
+  return (0);
+} /* int csnmp_config_add_host_priv_protocol */
+
+static int csnmp_config_add_host_security_level (host_definition_t *hd, oconfig_item_t *ci)
+{
+  char buffer[16];
+  int status;
+
+  status = cf_util_get_string_buffer(ci, buffer, sizeof(buffer));
+  if (status != 0)
+    return status;
+
+  if (strcasecmp("noAuthNoPriv", buffer) == 0)
+    hd->security_level = SNMP_SEC_LEVEL_NOAUTH;
+  else if (strcasecmp("authNoPriv", buffer) == 0)
+    hd->security_level = SNMP_SEC_LEVEL_AUTHNOPRIV;
+  else if (strcasecmp("authPriv", buffer) == 0)
+    hd->security_level = SNMP_SEC_LEVEL_AUTHPRIV;
+  else
+  {
+    WARNING ("snmp plugin: The `SecurityLevel' config option must be `noAuthNoPriv', `authNoPriv', or `authPriv'.");
+    return (-1);
+  }
+
+  DEBUG ("snmp plugin: host = %s; host->security_level = %d;",
+      hd->name, hd->security_level);
+
+  return (0);
+} /* int csnmp_config_add_host_security_level */
+
 static int csnmp_config_add_host (oconfig_item_t *ci)
 {
   host_definition_t *hd;
@@ -601,12 +643,6 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   user_data_t cb_data;
   struct timespec cb_interval;
 
-  if ((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING))
-  {
-    WARNING ("snmp plugin: `Host' needs exactly one string argument.");
-    return (-1);
-  }
-
   hd = (host_definition_t *) malloc (sizeof (host_definition_t));
   if (hd == NULL)
     return (-1);
@@ -614,12 +650,9 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
   hd->version = 2;
   C_COMPLAIN_INIT (&hd->complaint);
 
-  hd->name = strdup (ci->values[0].value.string);
-  if (hd->name == NULL)
-  {
-    free (hd);
-    return (-1);
-  }
+  status = cf_util_get_string(ci, &hd->name);
+  if (status != 0)
+    return status;
 
   hd->sess_handle = NULL;
   hd->interval = 0;
@@ -630,15 +663,29 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
     status = 0;
 
     if (strcasecmp ("Address", option->key) == 0)
-      status = csnmp_config_add_host_address (hd, option);
+      status = cf_util_get_string(option, &hd->address);
     else if (strcasecmp ("Community", option->key) == 0)
-      status = csnmp_config_add_host_community (hd, option);
+      status = cf_util_get_string(option, &hd->community);
     else if (strcasecmp ("Version", option->key) == 0)
       status = csnmp_config_add_host_version (hd, option);
     else if (strcasecmp ("Collect", option->key) == 0)
       csnmp_config_add_host_collect (hd, option);
     else if (strcasecmp ("Interval", option->key) == 0)
       cf_util_get_cdtime (option, &hd->interval);
+    else if (strcasecmp ("Username", option->key) == 0)
+      status = cf_util_get_string(option, &hd->username);
+    else if (strcasecmp ("AuthProtocol", option->key) == 0)
+      status = csnmp_config_add_host_auth_protocol (hd, option);
+    else if (strcasecmp ("PrivacyProtocol", option->key) == 0)
+      status = csnmp_config_add_host_priv_protocol (hd, option);
+    else if (strcasecmp ("AuthPassphrase", option->key) == 0)
+      status = cf_util_get_string(option, &hd->auth_passphrase);
+    else if (strcasecmp ("PrivacyPassphrase", option->key) == 0)
+      status = cf_util_get_string(option, &hd->priv_passphrase);
+    else if (strcasecmp ("SecurityLevel", option->key) == 0)
+      status = csnmp_config_add_host_security_level (hd, option);
+    else if (strcasecmp ("Context", option->key) == 0)
+      status = cf_util_get_string(option, &hd->context);
     else
     {
       WARNING ("snmp plugin: csnmp_config_add_host: Option `%s' not allowed here.", option->key);
@@ -657,12 +704,57 @@ static int csnmp_config_add_host (oconfig_item_t *ci)
       status = -1;
       break;
     }
-    if (hd->community == NULL)
+    if (hd->community == NULL && hd->version < 3)
     {
       WARNING ("snmp plugin: `Community' not given for host `%s'", hd->name);
       status = -1;
       break;
     }
+    if (hd->version == 3)
+    {
+      if (hd->username == NULL)
+      {
+        WARNING ("snmp plugin: `Username' not given for host `%s'", hd->name);
+        status = -1;
+        break;
+      }
+      if (hd->security_level == 0)
+      {
+        WARNING ("snmp plugin: `SecurityLevel' not given for host `%s'", hd->name);
+        status = -1;
+        break;
+      }
+      if (hd->security_level == SNMP_SEC_LEVEL_AUTHNOPRIV || hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
+      {
+       if (hd->auth_protocol == NULL)
+       {
+         WARNING ("snmp plugin: `AuthProtocol' not given for host `%s'", hd->name);
+         status = -1;
+         break;
+       }
+       if (hd->auth_passphrase == NULL)
+       {
+         WARNING ("snmp plugin: `AuthPassphrase' not given for host `%s'", hd->name);
+         status = -1;
+         break;
+       }
+      }
+      if (hd->security_level == SNMP_SEC_LEVEL_AUTHPRIV)
+      {
+       if (hd->priv_protocol == NULL)
+       {
+         WARNING ("snmp plugin: `PrivacyProtocol' not given for host `%s'", hd->name);
+         status = -1;
+         break;
+       }
+       if (hd->priv_passphrase == NULL)
+       {
+         WARNING ("snmp plugin: `PrivacyPassphrase' not given for host `%s'", hd->name);
+         status = -1;
+         break;
+       }
+      }
+    }
 
     break;
   } /* while (status == 0) */
@@ -724,15 +816,75 @@ static int csnmp_config (oconfig_item_t *ci)
 static void csnmp_host_open_session (host_definition_t *host)
 {
   struct snmp_session sess;
+  int error;
 
   if (host->sess_handle != NULL)
     csnmp_host_close_session (host);
 
   snmp_sess_init (&sess);
   sess.peername = host->address;
-  sess.community = (u_char *) host->community;
-  sess.community_len = strlen (host->community);
-  sess.version = (host->version == 1) ? SNMP_VERSION_1 : SNMP_VERSION_2c;
+  switch (host->version)
+  {
+    case 1:
+      sess.version = SNMP_VERSION_1;
+      break;
+    case 3:
+      sess.version = SNMP_VERSION_3;
+      break;
+    default:
+      sess.version = SNMP_VERSION_2c;
+      break;
+  }
+
+  if (host->version == 3)
+  {
+    sess.securityName = host->username;
+    sess.securityNameLen = strlen (host->username);
+    sess.securityLevel = host->security_level;
+
+    if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHNOPRIV || sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
+    {
+      sess.securityAuthProto = host->auth_protocol;
+      sess.securityAuthProtoLen = host->auth_protocol_len;
+      sess.securityAuthKeyLen = USM_AUTH_KU_LEN;
+      error = generate_Ku (sess.securityAuthProto,
+           sess.securityAuthProtoLen,
+           (u_char *) host->auth_passphrase,
+           strlen(host->auth_passphrase),
+           sess.securityAuthKey,
+           &sess.securityAuthKeyLen);
+      if (error != SNMPERR_SUCCESS) {
+       ERROR ("snmp plugin: host %s: Error generating Ku from auth_passphrase. (Error %d)", host->name, error);
+      }
+    }
+
+    if (sess.securityLevel == SNMP_SEC_LEVEL_AUTHPRIV)
+    {
+      sess.securityPrivProto = host->priv_protocol;
+      sess.securityPrivProtoLen = host->priv_protocol_len;
+      sess.securityPrivKeyLen = USM_PRIV_KU_LEN;
+      error = generate_Ku (sess.securityAuthProto,
+           sess.securityAuthProtoLen,
+           (u_char *) host->priv_passphrase,
+           strlen(host->priv_passphrase),
+           sess.securityPrivKey,
+           &sess.securityPrivKeyLen);
+      if (error != SNMPERR_SUCCESS) {
+       ERROR ("snmp plugin: host %s: Error generating Ku from priv_passphrase. (Error %d)", host->name, error);
+      }
+    }
+
+    if (host->context != NULL)
+    {
+      sess.contextName = host->context;
+      sess.contextNameLen = strlen (host->context);
+    }
+  }
+  else /* SNMPv1/2 "authenticates" with community string */
+  {
+    sess.community = (u_char *) host->community;
+    sess.community_len = strlen (host->community);
+  }
 
   /* snmp_sess_open will copy the `struct snmp_session *'. */
   host->sess_handle = snmp_sess_open (&sess);
@@ -971,6 +1123,8 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
   struct variable_list *vb;
   oid_t vb_name;
   int status;
+  uint32_t i;
+  uint32_t is_matched;
 
   /* Set vb on the last variable */
   for (vb = res->variables;
@@ -1004,7 +1158,29 @@ static int csnmp_instance_list_add (csnmp_list_instances_t **head,
     char *ptr;
 
     csnmp_strvbcopy (il->instance, vb, sizeof (il->instance));
-
+    is_matched = 0;
+    for (i = 0; i < dd->ignores_len; i++)
+    {
+      status = fnmatch(dd->ignores[i], il->instance, 0);
+      if (status == 0)
+      {
+        if (dd->invert_match == 0)
+        {
+          sfree(il);
+          return 0;
+        }
+       else
+       {
+          is_matched = 1;
+         break;
+       }
+      }
+    }
+    if (dd->invert_match != 0 && is_matched == 0)
+    {
+      sfree(il);
+      return 0;
+    }
     for (ptr = il->instance; *ptr != '\0'; ptr++)
     {
       if ((*ptr > 0) && (*ptr < 32))
@@ -1655,6 +1831,7 @@ static int csnmp_shutdown (void)
     sfree (data_this->name);
     sfree (data_this->type);
     sfree (data_this->values);
+    sfree (data_this->ignores);
     sfree (data_this);
 
     data_this = data_next;
index 0bd8e3a..3a7738f 100644 (file)
@@ -57,6 +57,8 @@ struct riemann_host {
 
 static char    **riemann_tags;
 static size_t    riemann_tags_num;
+static char    **riemann_attrs;
+static size_t     riemann_attrs_num;
 
 static void riemann_event_protobuf_free (Event *event) /* {{{ */
 {
@@ -422,6 +424,11 @@ static Msg *riemann_notification_to_protobuf (struct riemann_host *host, /* {{{
                riemann_event_add_attribute (event, "type_instance",
                                n->type_instance);
 
+       for (i = 0; i < riemann_attrs_num; i += 2)
+               riemann_event_add_attribute(event,
+                                           riemann_attrs[i],
+                                           riemann_attrs[i +1]);
+
        for (i = 0; i < riemann_tags_num; i++)
                riemann_event_add_tag (event, riemann_tags[i]);
 
@@ -511,6 +518,11 @@ static Event *riemann_value_to_protobuf (struct riemann_host const *host, /* {{{
                riemann_event_add_attribute (event, "ds_index", ds_index);
        }
 
+       for (i = 0; i < riemann_attrs_num; i += 2)
+               riemann_event_add_attribute(event,
+                                           riemann_attrs[i],
+                                           riemann_attrs[i +1]);
+
        for (i = 0; i < riemann_tags_num; i++)
                riemann_event_add_tag (event, riemann_tags[i]);
 
@@ -845,6 +857,32 @@ riemann_config(oconfig_item_t *ci)
 
                if (strcasecmp("Node", child->key) == 0) {
                        riemann_config_node (child);
+               } else if (strcasecmp(child->key, "attribute") == 0) {
+                       char *key = NULL;
+                       char *val = NULL;
+
+                       if (child->values_num != 2) {
+                               WARNING("riemann attributes need both a key and a value.");
+                               return (-1);
+                       }
+                       if (child->values[0].type != OCONFIG_TYPE_STRING ||
+                           child->values[1].type != OCONFIG_TYPE_STRING) {
+                               WARNING("riemann attribute needs string arguments.");
+                               return (-1);
+                       }
+                       if ((key = strdup(child->values[0].value.string)) == NULL) {
+                               WARNING("cannot allocate memory for attribute key.");
+                               return (-1);
+                       }
+                       if ((val = strdup(child->values[1].value.string)) == NULL) {
+                               WARNING("cannot allocate memory for attribute value.");
+                               return (-1);
+                       }
+                       strarray_add(&riemann_attrs, &riemann_attrs_num, key);
+                       strarray_add(&riemann_attrs, &riemann_attrs_num, val);
+                       DEBUG("write_riemann: got attr: %s => %s", key, val);
+                       sfree(key);
+                       sfree(val);
                } else if (strcasecmp(child->key, "tag") == 0) {
                        char *tmp = NULL;
                        status = cf_util_get_string(child, &tmp);