{GPL, other}: Relicense to MIT license.
[collectd.git] / src / interface.c
index 8947dd6..df8ffb4 100644 (file)
@@ -1,6 +1,7 @@
 /**
  * collectd - src/interface.c
- * Copyright (C) 2005-2008  Florian octo Forster
+ * Copyright (C) 2005-2010  Florian octo Forster
+ * Copyright (C) 2009       Manuel Sanmartin
  *
  * 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
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Sune Marcher <sm at flork.dk>
+ *   Manuel Sanmartin
  **/
 
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
 #include "configfile.h"
+#include "utils_ignorelist.h"
 
 #if HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 # include <statgrab.h>
 #endif
 
+#if HAVE_PERFSTAT
+# include <sys/protosw.h>
+# include <libperfstat.h>
+#endif
+
 /*
  * Various people have reported problems with `getifaddrs' and varying versions
  * of `glibc'. That's why it's disabled by default. Since more statistics are
 # endif /* !COLLECT_GETIFADDRS */
 #endif /* KERNEL_LINUX */
 
-#if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB
+#if HAVE_PERFSTAT
+static perfstat_netinterface_t *ifstat;
+static int nif;
+static int pnif;
+#endif /* HAVE_PERFSTAT */
+
+#if !HAVE_GETIFADDRS && !KERNEL_LINUX && !HAVE_LIBKSTAT && !HAVE_LIBSTATGRAB && !HAVE_PERFSTAT
 # error "No applicable input method."
 #endif
 
@@ -77,14 +91,7 @@ static const char *config_keys[] =
 };
 static int config_keys_num = 2;
 
-static char **if_list = NULL;
-static int    if_list_num = 0;
-/* 
- * if_list_action:
- * 0 => default is to collect selected interface
- * 1 => ignore selcted interfaces
- */
-static int    if_list_action = 0;
+static ignorelist_t *ignorelist = NULL;
 
 #ifdef HAVE_LIBKSTAT
 #define MAX_NUMIF 256
@@ -95,33 +102,19 @@ static int numif = 0;
 
 static int interface_config (const char *key, const char *value)
 {
-       char **temp;
+       if (ignorelist == NULL)
+               ignorelist = ignorelist_create (/* invert = */ 1);
 
        if (strcasecmp (key, "Interface") == 0)
        {
-               temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
-               if (temp == NULL)
-               {
-                       ERROR ("Cannot allocate more memory.");
-                       return (1);
-               }
-               if_list = temp;
-
-               if ((if_list[if_list_num] = strdup (value)) == NULL)
-               {
-                       ERROR ("Cannot allocate memory.");
-                       return (1);
-               }
-               if_list_num++;
+               ignorelist_add (ignorelist, value);
        }
        else if (strcasecmp (key, "IgnoreSelected") == 0)
        {
-               if ((strcasecmp (value, "True") == 0)
-                               || (strcasecmp (value, "Yes") == 0)
-                               || (strcasecmp (value, "On") == 0))
-                       if_list_action = 1;
-               else
-                       if_list_action = 0;
+               int invert = 1;
+               if (IS_TRUE (value))
+                       invert = 0;
+               ignorelist_set_invert (ignorelist, invert);
        }
        else
        {
@@ -135,7 +128,7 @@ static int interface_config (const char *key, const char *value)
 static int interface_init (void)
 {
        kstat_t *ksp_chain;
-       unsigned long long val;
+       derive_t val;
 
        numif = 0;
 
@@ -161,46 +154,25 @@ static int interface_init (void)
 } /* int interface_init */
 #endif /* HAVE_LIBKSTAT */
 
-/*
- * Check if this interface/instance should be ignored. This is called from
- * both, `submit' and `write' to give client and server the ability to
- * ignore certain stuff..
- */
-static int check_ignore_if (const char *interface)
-{
-       int i;
-
-       /* If no interfaces are given collect all interfaces. Mostly to be
-        * backwards compatible, but also because this is much easier. */
-       if (if_list_num < 1)
-               return (0);
-
-       for (i = 0; i < if_list_num; i++)
-               if (strcasecmp (interface, if_list[i]) == 0)
-                       return (if_list_action);
-       return (1 - if_list_action);
-} /* int check_ignore_if */
-
 static void if_submit (const char *dev, const char *type,
-               unsigned long long rx,
-               unsigned long long tx)
+               derive_t rx,
+               derive_t tx)
 {
        value_t values[2];
        value_list_t vl = VALUE_LIST_INIT;
 
-       if (check_ignore_if (dev))
+       if (ignorelist_match (ignorelist, dev) != 0)
                return;
 
-       values[0].counter = rx;
-       values[1].counter = tx;
+       values[0].derive = rx;
+       values[1].derive = tx;
 
        vl.values = values;
        vl.values_len = 2;
-       vl.time = time (NULL);
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "interface", sizeof (vl.plugin));
+       sstrncpy (vl.plugin_instance, dev, sizeof (vl.plugin_instance));
        sstrncpy (vl.type, type, sizeof (vl.type));
-       sstrncpy (vl.type_instance, dev, sizeof (vl.type_instance));
 
        plugin_dispatch_values (&vl);
 } /* void if_submit */
@@ -241,18 +213,19 @@ static int interface_read (void)
 
        for (if_ptr = if_list; if_ptr != NULL; if_ptr = if_ptr->ifa_next)
        {
-               if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
-                       continue;
+               if (if_ptr->ifa_addr != NULL && if_ptr->ifa_addr->sa_family == AF_LINK) {
+                       if_data = (struct IFA_DATA *) if_ptr->ifa_data;
 
-               if_submit (if_ptr->ifa_name, "if_octets",
+                       if_submit (if_ptr->ifa_name, "if_octets",
                                if_data->IFA_RX_BYTES,
                                if_data->IFA_TX_BYTES);
-               if_submit (if_ptr->ifa_name, "if_packets",
+                       if_submit (if_ptr->ifa_name, "if_packets",
                                if_data->IFA_RX_PACKT,
                                if_data->IFA_TX_PACKT);
-               if_submit (if_ptr->ifa_name, "if_errors",
+                       if_submit (if_ptr->ifa_name, "if_errors",
                                if_data->IFA_RX_ERROR,
                                if_data->IFA_TX_ERROR);
+               }
        }
 
        freeifaddrs (if_list);
@@ -261,9 +234,9 @@ static int interface_read (void)
 #elif KERNEL_LINUX
        FILE *fh;
        char buffer[1024];
-       unsigned long long incoming, outgoing;
+       derive_t incoming, outgoing;
        char *device;
-       
+
        char *dummy;
        char *fields[16];
        int numfields;
@@ -289,7 +262,7 @@ static int interface_read (void)
 
                if (device[0] == '\0')
                        continue;
-               
+
                numfields = strsplit (dummy, fields, 16);
 
                if (numfields < 11)
@@ -313,8 +286,8 @@ static int interface_read (void)
 
 #elif HAVE_LIBKSTAT
        int i;
-       unsigned long long rx;
-       unsigned long long tx;
+       derive_t rx;
+       derive_t tx;
 
        if (kc == NULL)
                return (-1);
@@ -324,16 +297,29 @@ static int interface_read (void)
                if (kstat_read (kc, ksp[i], NULL) == -1)
                        continue;
 
-               rx = get_kstat_value (ksp[i], "rbytes");
-               tx = get_kstat_value (ksp[i], "obytes");
+               /* try to get 64bit counters */
+               rx = get_kstat_value (ksp[i], "rbytes64");
+               tx = get_kstat_value (ksp[i], "obytes64");
+               /* or fallback to 32bit */
+               if (rx == -1LL)
+                       rx = get_kstat_value (ksp[i], "rbytes");
+               if (tx == -1LL)
+                       tx = get_kstat_value (ksp[i], "obytes");
                if ((rx != -1LL) || (tx != -1LL))
                        if_submit (ksp[i]->ks_name, "if_octets", rx, tx);
 
-               rx = get_kstat_value (ksp[i], "ipackets");
-               tx = get_kstat_value (ksp[i], "opackets");
+               /* try to get 64bit counters */
+               rx = get_kstat_value (ksp[i], "ipackets64");
+               tx = get_kstat_value (ksp[i], "opackets64");
+               /* or fallback to 32bit */
+               if (rx == -1LL)
+                       rx = get_kstat_value (ksp[i], "ipackets");
+               if (tx == -1LL)
+                       tx = get_kstat_value (ksp[i], "opackets");
                if ((rx != -1LL) || (tx != -1LL))
                        if_submit (ksp[i]->ks_name, "if_packets", rx, tx);
 
+               /* no 64bit error counters yet */
                rx = get_kstat_value (ksp[i], "ierrors");
                tx = get_kstat_value (ksp[i], "oerrors");
                if ((rx != -1LL) || (tx != -1LL))
@@ -349,7 +335,44 @@ static int interface_read (void)
 
        for (i = 0; i < num; i++)
                if_submit (ios[i].interface_name, "if_octets", ios[i].rx, ios[i].tx);
-#endif /* HAVE_LIBSTATGRAB */
+/* #endif HAVE_LIBSTATGRAB */
+
+#elif defined(HAVE_PERFSTAT)
+       perfstat_id_t id;
+       int i, ifs;
+
+       if ((nif =  perfstat_netinterface(NULL, NULL, sizeof(perfstat_netinterface_t), 0)) < 0)
+       {
+               char errbuf[1024];
+               WARNING ("interface plugin: perfstat_netinterface: %s",
+                       sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       if (pnif != nif || ifstat == NULL)
+       {
+               if (ifstat != NULL)
+                       free(ifstat);
+               ifstat = malloc(nif * sizeof(perfstat_netinterface_t));
+       }
+       pnif = nif;
+
+       id.name[0]='\0';
+       if ((ifs = perfstat_netinterface(&id, ifstat, sizeof(perfstat_netinterface_t), nif)) < 0)
+       {
+               char errbuf[1024];
+               WARNING ("interface plugin: perfstat_netinterface (interfaces=%d): %s",
+                       nif, sstrerror (errno, errbuf, sizeof (errbuf)));
+               return (-1);
+       }
+
+       for (i = 0; i < ifs; i++)
+       {
+               if_submit (ifstat[i].name, "if_octets", ifstat[i].ibytes, ifstat[i].obytes);
+               if_submit (ifstat[i].name, "if_packets", ifstat[i].ipackets ,ifstat[i].opackets);
+               if_submit (ifstat[i].name, "if_errors", ifstat[i].ierrors, ifstat[i].oerrors );
+       }
+#endif /* HAVE_PERFSTAT */
 
        return (0);
 } /* int interface_read */