X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=src%2Ftraffic.c;h=a7b70c5875a6d3946964b5896013437da3afa437;hb=062770152a71a4bb053edbc5d8983b650eb805e5;hp=66f2b13359f47e6fd154c3dcc024343c8a826345;hpb=7fa270a1fb517c7fbed55d9f5f70bb28516b6229;p=collectd.git diff --git a/src/traffic.c b/src/traffic.c index 66f2b133..a7b70c58 100644 --- a/src/traffic.c +++ b/src/traffic.c @@ -1,11 +1,10 @@ /** * collectd - src/traffic.c - * Copyright (C) 2005 Florian octo Forster + * Copyright (C) 2005,2006 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 @@ -18,15 +17,106 @@ * * Authors: * Florian octo Forster + * Sune Marcher **/ -#include "traffic.h" +#include "collectd.h" +#include "common.h" +#include "plugin.h" +#include "configfile.h" + +#if HAVE_SYS_TYPES_H +# include +#endif +#if HAVE_SYS_SOCKET_H +# include +#endif + +/* One cannot include both. This sucks. */ +#if HAVE_LINUX_IF_H +# include +#elif HAVE_NET_IF_H +# include +#endif + +#if HAVE_LINUX_NETDEVICE_H +# include +#endif +#if HAVE_IFADDRS_H +# include +#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 + * available this way one may enable it using the `--enable-getifaddrs' option + * of the configure script. -octo + */ +#if KERNEL_LINUX +# if !COLLECT_GETIFADDRS +# undef HAVE_GETIFADDRS +# endif /* !COLLECT_GETIFADDRS */ +#endif /* KERNEL_LINUX */ + +#if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_LIBSTATGRAB +# define TRAFFIC_HAVE_READ 1 +#else +# define TRAFFIC_HAVE_READ 0 +#endif + +/* + * (Module-)Global variables + */ +/* 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} +}; -#if COLLECT_TRAFFIC -#define MODULE_NAME "traffic" +static data_set_t octets_ds = +{ + "if_octets", 2, octets_dsrc +}; -#include "plugin.h" -#include "common.h" +static data_source_t packets_dsrc[2] = +{ + {"rx", DS_TYPE_COUNTER, 0, 4294967295.0}, + {"tx", DS_TYPE_COUNTER, 0, 4294967295.0} +}; + +static data_set_t packets_ds = +{ + "if_packets", 2, packets_dsrc +}; + +static data_source_t errors_dsrc[2] = +{ + {"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 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 @@ -35,29 +125,55 @@ static kstat_t *ksp[MAX_NUMIF]; static int numif = 0; #endif /* HAVE_LIBKSTAT */ -static char *traffic_filename_template = "traffic-%s.rrd"; - -static char *ds_def[] = +static int interface_config (const char *key, const char *value) { - "DS:incoming:COUNTER:25:0:U", - "DS:outgoing:COUNTER:25:0:U", - NULL -}; -static int ds_num = 2; + char **temp; -extern time_t curtime; + 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; + + 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) + { + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + if_list_action = 1; + else + if_list_action = 0; + } + else + { + return (-1); + } -void traffic_init (void) + return (0); +} + +#if HAVE_LIBKSTAT +static int traffic_init (void) { -#ifdef HAVE_LIBKSTAT +#if HAVE_LIBKSTAT kstat_t *ksp_chain; - kstat_named_t *kn; 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); @@ -74,39 +190,110 @@ void traffic_init (void) ksp[numif++] = ksp_chain; } #endif /* HAVE_LIBKSTAT */ -} -void traffic_write (char *host, char *inst, char *val) + 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.. + */ +static int check_ignore_if (const char *interface) { - char file[512]; - int status; + int i; - status = snprintf (file, 512, traffic_filename_template, inst); - if (status < 1) - return; - else if (status >= 512) + /* 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 TRAFFIC_HAVE_READ +static void if_submit (const char *dev, const char *type, + unsigned long long rx, + unsigned long long tx) +{ + value_t values[2]; + value_list_t vl = VALUE_LIST_INIT; + + if (check_ignore_if (dev)) return; - rrd_update_file (host, file, val, ds_def, ds_num); -} + values[0].counter = rx; + values[1].counter = tx; -#define BUFSIZE 512 -void traffic_submit (char *device, - unsigned long long incoming, - unsigned long long outgoing) -{ - char buf[BUFSIZE]; + 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)); + + plugin_dispatch_values (type, &vl); +} /* void if_submit */ - if (snprintf (buf, BUFSIZE, "%u:%lld:%lld", (unsigned int) curtime, incoming, outgoing) >= BUFSIZE) +static int traffic_read (void) +{ +#if HAVE_GETIFADDRS + struct ifaddrs *if_list; + struct ifaddrs *if_ptr; + +/* Darin/Mac OS X and possible other *BSDs */ +#if HAVE_STRUCT_IF_DATA +# define IFA_DATA if_data +# define IFA_RX_BYTES ifi_ibytes +# define IFA_TX_BYTES ifi_obytes +# define IFA_RX_PACKT ifi_ipackets +# define IFA_TX_PACKT ifi_opackets +# define IFA_RX_ERROR ifi_ierrors +# define IFA_TX_ERROR ifi_oerrors +/* #endif HAVE_STRUCT_IF_DATA */ + +#elif HAVE_STRUCT_NET_DEVICE_STATS +# define IFA_DATA net_device_stats +# define IFA_RX_BYTES rx_bytes +# define IFA_TX_BYTES tx_bytes +# define IFA_RX_PACKT rx_packets +# define IFA_TX_PACKT tx_packets +# define IFA_RX_ERROR rx_errors +# define IFA_TX_ERROR tx_errors +#else +# error "No suitable type for `struct ifaddrs->ifa_data' found." +#endif + + struct IFA_DATA *if_data; + + if (getifaddrs (&if_list) != 0) return; - plugin_submit (MODULE_NAME, device, buf); -} -#undef BUFSIZE + 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; -void traffic_read (void) -{ -#ifdef KERNEL_LINUX + 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_data->IFA_RX_PACKT, + if_data->IFA_TX_PACKT); + if_submit (if_ptr->ifa_name, "if_errors", + if_data->IFA_RX_ERROR, + if_data->IFA_TX_ERROR); + } + + freeifaddrs (if_list); +/* #endif HAVE_GETIFADDRS */ + +#elif KERNEL_LINUX FILE *fh; char buffer[1024]; unsigned long long incoming, outgoing; @@ -119,14 +306,15 @@ 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) { - if (buffer[6] != ':') + if (!(dummy = strchr(buffer, ':'))) continue; - buffer[6] = '\0'; + dummy[0] = '\0'; + dummy++; device = buffer; while (device[0] == ' ') @@ -135,24 +323,31 @@ void traffic_read (void) if (device[0] == '\0') continue; - dummy = buffer + 7; numfields = strsplit (dummy, fields, 16); - if (numfields < 9) + if (numfields < 11) continue; incoming = atoll (fields[0]); outgoing = atoll (fields[8]); + if_submit (device, "if_octets", incoming, outgoing); + + incoming = atoll (fields[1]); + outgoing = atoll (fields[9]); + if_submit (device, "if_packets", incoming, outgoing); - traffic_submit (device, incoming, outgoing); + incoming = atoll (fields[2]); + outgoing = atoll (fields[10]); + if_submit (device, "if_errors", incoming, outgoing); } fclose (fh); /* #endif KERNEL_LINUX */ -#elif defined(HAVE_LIBKSTAT) +#elif HAVE_LIBKSTAT int i; - unsigned long long incoming, outgoing; + unsigned long long rx; + unsigned long long tx; if (kc == NULL) return; @@ -162,12 +357,20 @@ void traffic_read (void) if (kstat_read (kc, ksp[i], NULL) == -1) continue; - if ((incoming = get_kstat_value (ksp[i], "rbytes")) == -1LL) - continue; - if ((outgoing = get_kstat_value (ksp[i], "obytes")) == -1LL) - continue; + rx = get_kstat_value (ksp[i], "rbytes"); + 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"); + if ((rx != -1LL) || (tx != -1LL)) + if_submit (ksp[i]->ks_name, "if_packets", rx, tx); - traffic_submit (ksp[i]->ks_name, incoming, outgoing); + rx = get_kstat_value (ksp[i], "ierrors"); + tx = get_kstat_value (ksp[i], "oerrors"); + if ((rx != -1LL) || (tx != -1LL)) + if_submit (ksp[i]->ks_name, "if_errors", rx, tx); } /* #endif HAVE_LIBKSTAT */ @@ -178,14 +381,27 @@ void traffic_read (void) ios = sg_get_network_io_stats (&num); for (i = 0; i < num; i++) - traffic_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 */ -} + + return (0); +} /* int traffic_read */ +#endif /* TRAFFIC_HAVE_READ */ void module_register (void) { - plugin_register (MODULE_NAME, traffic_init, traffic_read, traffic_write); -} + 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 MODULE_NAME -#endif /* COLLECT_TRAFFIC */ +#if HAVE_LIBKSTAT + plugin_register_init ("interface", traffic_init); +#endif + +#if TRAFFIC_HAVE_READ + plugin_register_read ("interface", traffic_read); +#endif +}