Code

5bf9a502d417ab058d214271045292bd66b454c8
[collectd.git] / src / traffic.c
1 /**
2  * collectd - src/traffic.c
3  * Copyright (C) 2005,2006  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #if HAVE_SYS_TYPES_H
28 #  include <sys/types.h>
29 #endif
30 #if HAVE_SYS_SOCKET_H
31 #  include <sys/socket.h>
32 #endif
34 /* One cannot include both. This sucks. */
35 #if HAVE_LINUX_IF_H
36 #  include <linux/if.h>
37 #elif HAVE_NET_IF_H
38 #  include <net/if.h>
39 #endif
41 #if HAVE_LINUX_NETDEVICE_H
42 #  include <linux/netdevice.h>
43 #endif
44 #if HAVE_IFADDRS_H
45 #  include <ifaddrs.h>
46 #endif
48 #define MODULE_NAME "traffic"
50 #if HAVE_GETIFADDRS || KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_LIBSTATGRAB
51 # define TRAFFIC_HAVE_READ 1
52 #else
53 # define TRAFFIC_HAVE_READ 0
54 #endif
56 #define BUFSIZE 512
58 static char *bytes_file   = "traffic-%s.rrd";
59 static char *packets_file = "interface-%s/packets.rrd";
60 static char *errors_file  = "interface-%s/errors.rrd";
62 static char *bytes_ds_def[] =
63 {
64         "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
65         "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
66         NULL
67 };
68 static int bytes_ds_num = 2;
70 static char *packets_ds_def[] =
71 {
72         "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
73         "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
74         NULL
75 };
76 static int packets_ds_num = 2;
78 static char *errors_ds_def[] =
79 {
80         "DS:rx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
81         "DS:tx:COUNTER:"COLLECTD_HEARTBEAT":0:U",
82         NULL
83 };
84 static int errors_ds_num = 2;
86 #ifdef HAVE_LIBKSTAT
87 #define MAX_NUMIF 256
88 extern kstat_ctl_t *kc;
89 static kstat_t *ksp[MAX_NUMIF];
90 static int numif = 0;
91 #endif /* HAVE_LIBKSTAT */
93 static void traffic_init (void)
94 {
95 #if HAVE_GETIFADDRS
96         /* nothing */
97 /* #endif HAVE_GETIFADDRS */
99 #elif KERNEL_LINUX
100         /* nothing */
101 /* #endif KERNEL_LINUX */
103 #elif HAVE_LIBKSTAT
104         kstat_t *ksp_chain;
105         unsigned long long val;
107         numif = 0;
109         if (kc == NULL)
110                 return;
112         for (numif = 0, ksp_chain = kc->kc_chain;
113                         (numif < MAX_NUMIF) && (ksp_chain != NULL);
114                         ksp_chain = ksp_chain->ks_next)
115         {
116                 if (strncmp (ksp_chain->ks_class, "net", 3))
117                         continue;
118                 if (ksp_chain->ks_type != KSTAT_TYPE_NAMED)
119                         continue;
120                 if (kstat_read (kc, ksp_chain, NULL) == -1)
121                         continue;
122                 if ((val = get_kstat_value (ksp_chain, "obytes")) == -1LL)
123                         continue;
124                 ksp[numif++] = ksp_chain;
125         }
126 /* #endif HAVE_LIBKSTAT */
128 #elif HAVE_LIBSTATG
129         /* nothing */
130 #endif /* HAVE_LIBSTATG */
132         return;
135 static void generic_write (char *host, char *inst, char *val,
136                 char *file_template,
137                 char **ds_def, int ds_num)
139         char file[512];
140         int status;
142         status = snprintf (file, BUFSIZE, file_template, inst);
143         if (status < 1)
144                 return;
145         else if (status >= 512)
146                 return;
148         rrd_update_file (host, file, val, ds_def, ds_num);
151 static void bytes_write (char *host, char *inst, char *val)
153         generic_write (host, inst, val, bytes_file, bytes_ds_def, bytes_ds_num);
156 static void packets_write (char *host, char *inst, char *val)
158         generic_write (host, inst, val, packets_file, packets_ds_def, packets_ds_num);
161 static void errors_write (char *host, char *inst, char *val)
163         generic_write (host, inst, val, errors_file, errors_ds_def, errors_ds_num);
166 #if TRAFFIC_HAVE_READ
167 static void bytes_submit (char *device,
168                 unsigned long long incoming,
169                 unsigned long long outgoing)
171         char buf[BUFSIZE];
173         if (snprintf (buf, BUFSIZE, "%u:%lld:%lld", (unsigned int) curtime, incoming, outgoing) >= BUFSIZE)
174                 return;
176         plugin_submit (MODULE_NAME, device, buf);
179 #if HAVE_GETIFADDRS
180 static void packets_submit (char *dev,
181                 unsigned long long rx,
182                 unsigned long long tx)
184         char buf[512];
185         int  status;
187         status = snprintf (buf, 512, "%u:%lld:%lld",
188                         (unsigned int) curtime,
189                         rx, tx);
190         if ((status >= 512) || (status < 1))
191                 return;
192         plugin_submit ("if_packets", dev, buf);
195 static void errors_submit (char *dev,
196                 unsigned long long rx,
197                 unsigned long long tx)
199         char buf[512];
200         int  status;
202         status = snprintf (buf, 512, "%u:%lld:%lld",
203                         (unsigned int) curtime,
204                         rx, tx);
205         if ((status >= 512) || (status < 1))
206                 return;
207         plugin_submit ("if_errors", dev, buf);
209 #endif /* HAVE_GETIFADDRS */
211 static void traffic_read (void)
213 #if HAVE_GETIFADDRS
214         struct ifaddrs *if_list;
215         struct ifaddrs *if_ptr;
217 /* Darin/Mac OS X and possible other *BSDs */
218 #if HAVE_STRUCT_IF_DATA
219 #  define IFA_DATA if_data
220 #  define IFA_RX_BYTES ifi_ibytes
221 #  define IFA_TX_BYTES ifi_obytes
222 #  define IFA_RX_PACKT ifi_ipackets
223 #  define IFA_TX_PACKT ifi_opackets
224 #  define IFA_RX_ERROR ifi_ierrors
225 #  define IFA_TX_ERROR ifi_oerrors
226 /* #endif HAVE_STRUCT_IF_DATA */
228 #elif HAVE_STRUCT_NET_DEVICE_STATS
229 #  define IFA_DATA net_device_stats
230 #  define IFA_RX_BYTES rx_bytes
231 #  define IFA_TX_BYTES tx_bytes
232 #  define IFA_RX_PACKT rx_packets
233 #  define IFA_TX_PACKT tx_packets
234 #  define IFA_RX_ERROR rx_errors
235 #  define IFA_TX_ERROR tx_errors
236 #else
237 #  error "No suitable type for `struct ifaddrs->ifa_data' found."
238 #endif
240         struct IFA_DATA *if_data;
242         if (getifaddrs (&if_list) != 0)
243                 return;
245         for (if_ptr = if_list; if_ptr != NULL; if_ptr = if_ptr->ifa_next)
246         {
247                 if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
248                         continue;
250                 bytes_submit (if_ptr->ifa_name,
251                                 if_data->IFA_RX_BYTES,
252                                 if_data->IFA_TX_BYTES);
253                 packets_submit (if_ptr->ifa_name,
254                                 if_data->IFA_RX_PACKT,
255                                 if_data->IFA_TX_PACKT);
256                 errors_submit (if_ptr->ifa_name,
257                                 if_data->IFA_RX_ERROR,
258                                 if_data->IFA_TX_ERROR);
259         }
261         freeifaddrs (if_list);
262 /* #endif HAVE_GETIFADDRS */
264 #elif KERNEL_LINUX
265         FILE *fh;
266         char buffer[1024];
267         unsigned long long incoming, outgoing;
268         char *device;
269         
270         char *dummy;
271         char *fields[16];
272         int numfields;
274         if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
275         {
276                 syslog (LOG_WARNING, "traffic: fopen: %s", strerror (errno));
277                 return;
278         }
280         while (fgets (buffer, 1024, fh) != NULL)
281         {
282                 if (buffer[6] != ':')
283                         continue;
284                 buffer[6] = '\0';
286                 device = buffer;
287                 while (device[0] == ' ')
288                         device++;
290                 if (device[0] == '\0')
291                         continue;
292                 
293                 dummy = buffer + 7;
294                 numfields = strsplit (dummy, fields, 16);
296                 if (numfields < 9)
297                         continue;
299                 incoming = atoll (fields[0]);
300                 outgoing = atoll (fields[8]);
302                 bytes_submit (device, incoming, outgoing);
303         }
305         fclose (fh);
306 /* #endif KERNEL_LINUX */
308 #elif defined(HAVE_LIBKSTAT)
309         int i;
310         unsigned long long incoming, outgoing;
312         if (kc == NULL)
313                 return;
315         for (i = 0; i < numif; i++)
316         {
317                 if (kstat_read (kc, ksp[i], NULL) == -1)
318                         continue;
320                 if ((incoming = get_kstat_value (ksp[i], "rbytes")) == -1LL)
321                         continue;
322                 if ((outgoing = get_kstat_value (ksp[i], "obytes")) == -1LL)
323                         continue;
325                 bytes_submit (ksp[i]->ks_name, incoming, outgoing);
326         }
327 /* #endif HAVE_LIBKSTAT */
329 #elif defined(HAVE_LIBSTATGRAB)
330         sg_network_io_stats *ios;
331         int i, num;
333         ios = sg_get_network_io_stats (&num);
335         for (i = 0; i < num; i++)
336                 bytes_submit (ios[i].interface_name, ios[i].rx, ios[i].tx);
337 #endif /* HAVE_LIBSTATGRAB */
339 #else
340 #define traffic_read NULL
341 #endif /* TRAFFIC_HAVE_READ */
343 void module_register (void)
345         plugin_register (MODULE_NAME, traffic_init, traffic_read, bytes_write);
346         plugin_register ("if_packets", NULL, NULL, packets_write);
347         plugin_register ("if_errors",  NULL, NULL, errors_write);
350 #undef BUFSIZE
351 #undef MODULE_NAME