/**
* collectd - src/interface.c
- * Copyright (C) 2005-2007 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
* Authors:
* Florian octo Forster <octo at verplant.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 <ifaddrs.h>
#endif
+#if HAVE_STATGRAB_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
-# define INTERFACE_HAVE_READ 1
-#else
-# define INTERFACE_HAVE_READ 0
+#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
/*
};
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
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
{
#if HAVE_LIBKSTAT
static int interface_init (void)
{
-#if HAVE_LIBKSTAT
kstat_t *ksp_chain;
- unsigned long long val;
+ derive_t val;
numif = 0;
continue;
ksp[numif++] = ksp_chain;
}
-#endif /* HAVE_LIBKSTAT */
return (0);
} /* 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 */
-
-#if INTERFACE_HAVE_READ
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);
- strcpy (vl.host, hostname_g);
- strcpy (vl.plugin, "interface");
- strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
+ 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));
- plugin_dispatch_values (type, &vl);
+ plugin_dispatch_values (&vl);
} /* void if_submit */
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);
#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;
if (device[0] == '\0')
continue;
-
+
numfields = strsplit (dummy, fields, 16);
if (numfields < 11)
#elif HAVE_LIBKSTAT
int i;
- unsigned long long rx;
- unsigned long long tx;
+ derive_t rx;
+ derive_t tx;
if (kc == NULL)
- return;
+ return (-1);
for (i = 0; i < numif; i++)
{
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))
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 */
-#endif /* INTERFACE_HAVE_READ */
void module_register (void)
{
#if HAVE_LIBKSTAT
plugin_register_init ("interface", interface_init);
#endif
-#if INTERFACE_HAVE_READ
plugin_register_read ("interface", interface_read);
-#endif
} /* void module_register */