Merge branch 'pull/collectd-4'
[collectd.git] / src / traffic.c
index d12f5e4..e08dc14 100644 (file)
@@ -1,11 +1,10 @@
 /**
  * collectd - src/traffic.c
- * Copyright (C) 2005,2006  Florian octo Forster
+ * Copyright (C) 2005-2007  Florian octo Forster
  *
  * 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
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
+ * Free Software Foundation; only version 2 of the License is applicable.
  *
  * This program is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -47,8 +46,6 @@
 #  include <ifaddrs.h>
 #endif
 
-#define MODULE_NAME "traffic"
-
 /*
  * Various people have reported problems with `getifaddrs' and varying versions
  * of `glibc'. That's why it's disabled by default. Since more statistics are
 # define TRAFFIC_HAVE_READ 0
 #endif
 
-#define BUFSIZE 512
-
 /*
  * (Module-)Global variables
  */
-/* TODO: Move this to `interface-%s/<blah>.rrd' in version 4. */
-static char *bytes_file   = "traffic-%s.rrd";
-static char *packets_file = "if_packets-%s.rrd";
-static char *errors_file  = "if_errors-%s.rrd";
-/* TODO: Maybe implement multicast and broadcast counters */
+/* 2^32 = 4294967296 = ~4.2GByte/s = ~34GBit/s */
+static data_source_t octets_dsrc[2] =
+{
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
 
-static char *config_keys[] =
+static data_set_t octets_ds =
 {
-       "Ignore",
-       NULL
+       "if_octets", 2, octets_dsrc
 };
-static int config_keys_num = 1;
 
-static char *bytes_ds_def[] =
+static data_source_t packets_dsrc[2] =
 {
-       "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
 };
-static int bytes_ds_num = 2;
 
-static char *packets_ds_def[] =
+static data_set_t packets_ds =
 {
-       "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       "if_packets", 2, packets_dsrc
 };
-static int packets_ds_num = 2;
 
-static char *errors_ds_def[] =
+static data_source_t errors_dsrc[2] =
 {
-       "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
-       NULL
+       {"rx", DS_TYPE_COUNTER, 0, 4294967295.0},
+       {"tx", DS_TYPE_COUNTER, 0, 4294967295.0}
+};
+
+static data_set_t errors_ds =
+{
+       "if_errors", 2, errors_dsrc
 };
-static int errors_ds_num = 2;
 
-static char **if_ignore_list = NULL;
-static int    if_ignore_list_num = 0;
+static const char *config_keys[] =
+{
+       "Interface",
+       "IgnoreSelected",
+       NULL
+};
+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;
 
 #ifdef HAVE_LIBKSTAT
 #define MAX_NUMIF 256
@@ -119,51 +125,55 @@ static kstat_t *ksp[MAX_NUMIF];
 static int numif = 0;
 #endif /* HAVE_LIBKSTAT */
 
-static int traffic_config (char *key, char *value)
+static int interface_config (const char *key, const char *value)
 {
        char **temp;
 
-       if (strcasecmp (key, "Ignore") != 0)
-               return (-1);
+       if (strcasecmp (key, "Interface") == 0)
+       {
+               temp = (char **) realloc (if_list, (if_list_num + 1) * sizeof (char *));
+               if (temp == NULL)
+               {
+                       syslog (LOG_EMERG, "Cannot allocate more memory.");
+                       return (1);
+               }
+               if_list = temp;
 
-       temp = (char **) realloc (if_ignore_list, (if_ignore_list_num + 1) * sizeof (char *));
-       if (temp == NULL)
+               if ((if_list[if_list_num] = strdup (value)) == NULL)
+               {
+                       syslog (LOG_EMERG, "Cannot allocate memory.");
+                       return (1);
+               }
+               if_list_num++;
+       }
+       else if (strcasecmp (key, "IgnoreSelected") == 0)
        {
-               syslog (LOG_EMERG, "Cannot allocate more memory.");
-               return (1);
+               if ((strcasecmp (value, "True") == 0)
+                               || (strcasecmp (value, "Yes") == 0)
+                               || (strcasecmp (value, "On") == 0))
+                       if_list_action = 1;
+               else
+                       if_list_action = 0;
        }
-       if_ignore_list = temp;
-
-       if ((if_ignore_list[if_ignore_list_num] = strdup (value)) == NULL)
+       else
        {
-               syslog (LOG_EMERG, "Cannot allocate memory.");
-               return (1);
+               return (-1);
        }
-       if_ignore_list_num++;
-
-       syslog (LOG_NOTICE, "traffic: Ignoring interface `%s'", value);
 
        return (0);
 }
 
-static void traffic_init (void)
+#if HAVE_LIBKSTAT
+static int traffic_init (void)
 {
-#if HAVE_GETIFADDRS
-       /* nothing */
-/* #endif HAVE_GETIFADDRS */
-
-#elif KERNEL_LINUX
-       /* nothing */
-/* #endif KERNEL_LINUX */
-
-#elif HAVE_LIBKSTAT
+#if HAVE_LIBKSTAT
        kstat_t *ksp_chain;
        unsigned long long val;
 
        numif = 0;
 
        if (kc == NULL)
-               return;
+               return (-1);
 
        for (numif = 0, ksp_chain = kc->kc_chain;
                        (numif < MAX_NUMIF) && (ksp_chain != NULL);
@@ -179,123 +189,58 @@ static void traffic_init (void)
                        continue;
                ksp[numif++] = ksp_chain;
        }
-/* #endif HAVE_LIBKSTAT */
-
-#elif HAVE_LIBSTATG
-       /* nothing */
-#endif /* HAVE_LIBSTATG */
+#endif /* HAVE_LIBKSTAT */
 
-       return;
-}
+       return (0);
+} /* int traffic_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..
+ * 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;
 
-       for (i = 0; i < if_ignore_list_num; i++)
-               if (strcasecmp (interface, if_ignore_list[i]) == 0)
-                       return (1);
-       return (0);
-}
-
-static void generic_write (char *host, char *inst, char *val,
-               char *file_template,
-               char **ds_def, int ds_num)
-{
-       char file[512];
-       int status;
-
-       if (check_ignore_if (inst))
-               return;
-
-       status = snprintf (file, BUFSIZE, file_template, inst);
-       if (status < 1)
-               return;
-       else if (status >= 512)
-               return;
-
-       rrd_update_file (host, file, val, ds_def, ds_num);
-}
-
-static void bytes_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, bytes_file, bytes_ds_def, bytes_ds_num);
-}
-
-static void packets_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, packets_file, packets_ds_def, packets_ds_num);
-}
+       /* 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);
 
-static void errors_write (char *host, char *inst, char *val)
-{
-       generic_write (host, inst, val, errors_file, errors_ds_def, errors_ds_num);
-}
+       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 TRAFFIC_HAVE_READ
-static void bytes_submit (char *dev,
+static void if_submit (const char *dev, const char *type,
                unsigned long long rx,
                unsigned long long tx)
 {
-       char buf[512];
-       int  status;
+       value_t values[2];
+       value_list_t vl = VALUE_LIST_INIT;
 
        if (check_ignore_if (dev))
                return;
 
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                               (unsigned int) curtime,
-                               rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-
-       plugin_submit (MODULE_NAME, dev, buf);
-}
-
-#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT
-static void packets_submit (char *dev,
-               unsigned long long rx,
-               unsigned long long tx)
-{
-       char buf[512];
-       int  status;
+       values[0].counter = rx;
+       values[1].counter = tx;
 
-       if (check_ignore_if (dev))
-               return;
+       vl.values = values;
+       vl.values_len = 2;
+       vl.time = time (NULL);
+       strcpy (vl.host, hostname);
+       strcpy (vl.plugin, "interface");
+       strcpy (vl.plugin_instance, "");
+       strncpy (vl.type_instance, dev, sizeof (vl.type_instance));
 
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                       (unsigned int) curtime,
-                       rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-       plugin_submit ("if_packets", dev, buf);
-}
+       plugin_dispatch_values (type, &vl);
+} /* void if_submit */
 
-static void errors_submit (char *dev,
-               unsigned long long rx,
-               unsigned long long tx)
-{
-       char buf[512];
-       int  status;
-
-       if (check_ignore_if (dev))
-               return;
-
-       status = snprintf (buf, 512, "%u:%lld:%lld",
-                       (unsigned int) curtime,
-                       rx, tx);
-       if ((status >= 512) || (status < 1))
-               return;
-       plugin_submit ("if_errors", dev, buf);
-}
-#endif /* HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT */
-
-static void traffic_read (void)
+static int traffic_read (void)
 {
 #if HAVE_GETIFADDRS
        struct ifaddrs *if_list;
@@ -327,20 +272,20 @@ static void traffic_read (void)
        struct IFA_DATA *if_data;
 
        if (getifaddrs (&if_list) != 0)
-               return;
+               return (-1);
 
        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;
 
-               bytes_submit (if_ptr->ifa_name,
+               if_submit (if_ptr->ifa_name, "if_octets",
                                if_data->IFA_RX_BYTES,
                                if_data->IFA_TX_BYTES);
-               packets_submit (if_ptr->ifa_name,
+               if_submit (if_ptr->ifa_name, "if_packets",
                                if_data->IFA_RX_PACKT,
                                if_data->IFA_TX_PACKT);
-               errors_submit (if_ptr->ifa_name,
+               if_submit (if_ptr->ifa_name, "if_errors",
                                if_data->IFA_RX_ERROR,
                                if_data->IFA_TX_ERROR);
        }
@@ -361,7 +306,7 @@ static void traffic_read (void)
        if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
        {
                syslog (LOG_WARNING, "traffic: fopen: %s", strerror (errno));
-               return;
+               return (-1);
        }
 
        while (fgets (buffer, 1024, fh) != NULL)
@@ -385,15 +330,15 @@ static void traffic_read (void)
 
                incoming = atoll (fields[0]);
                outgoing = atoll (fields[8]);
-               bytes_submit (device, incoming, outgoing);
+               if_submit (device, "if_octets", incoming, outgoing);
 
                incoming = atoll (fields[1]);
                outgoing = atoll (fields[9]);
-               packets_submit (device, incoming, outgoing);
+               if_submit (device, "if_packets", incoming, outgoing);
 
                incoming = atoll (fields[2]);
                outgoing = atoll (fields[10]);
-               errors_submit (device, incoming, outgoing);
+               if_submit (device, "if_errors", incoming, outgoing);
        }
 
        fclose (fh);
@@ -415,17 +360,17 @@ static void traffic_read (void)
                rx = get_kstat_value (ksp[i], "rbytes");
                tx = get_kstat_value (ksp[i], "obytes");
                if ((rx != -1LL) || (tx != -1LL))
-                       bytes_submit (ksp[i]->ks_name, rx, tx);
+                       if_submit (ksp[i]->ks_name, "if_octets", rx, tx);
 
                rx = get_kstat_value (ksp[i], "ipackets");
                tx = get_kstat_value (ksp[i], "opackets");
                if ((rx != -1LL) || (tx != -1LL))
-                       packets_submit (ksp[i]->ks_name, rx, tx);
+                       if_submit (ksp[i]->ks_name, "if_packets", rx, tx);
 
                rx = get_kstat_value (ksp[i], "ierrors");
                tx = get_kstat_value (ksp[i], "oerrors");
                if ((rx != -1LL) || (tx != -1LL))
-                       errors_submit (ksp[i]->ks_name, rx, tx);
+                       if_submit (ksp[i]->ks_name, "if_errors", rx, tx);
        }
 /* #endif HAVE_LIBKSTAT */
 
@@ -436,20 +381,27 @@ static void traffic_read (void)
        ios = sg_get_network_io_stats (&num);
 
        for (i = 0; i < num; i++)
-               bytes_submit (ios[i].interface_name, ios[i].rx, ios[i].tx);
+               if_submit (ios[i].interface_name, "if_octets", ios[i].rx, ios[i].tx);
 #endif /* HAVE_LIBSTATGRAB */
-}
-#else
-#define traffic_read NULL
+
+       return (0);
+} /* int traffic_read */
 #endif /* TRAFFIC_HAVE_READ */
 
 void module_register (void)
 {
-       plugin_register (MODULE_NAME, traffic_init, traffic_read, bytes_write);
-       plugin_register ("if_packets", NULL, NULL, packets_write);
-       plugin_register ("if_errors",  NULL, NULL, errors_write);
-       cf_register (MODULE_NAME, traffic_config, config_keys, config_keys_num);
-}
+       plugin_register_data_set (&octets_ds);
+       plugin_register_data_set (&packets_ds);
+       plugin_register_data_set (&errors_ds);
+
+       plugin_register_config ("interface", interface_config,
+                       config_keys, config_keys_num);
 
-#undef BUFSIZE
-#undef MODULE_NAME
+#if HAVE_LIBKSTAT
+       plugin_register_init ("interface", traffic_init);
+#endif
+
+#if TRAFFIC_HAVE_READ
+       plugin_register_read ("interface", traffic_read);
+#endif
+}