Updated all copyright-entries in header files.
[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  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
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
33
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
40
41 #if HAVE_LINUX_NETDEVICE_H
42 #  include <linux/netdevice.h>
43 #endif
44 #if HAVE_IFADDRS_H
45 #  include <ifaddrs.h>
46 #endif
47
48 #define MODULE_NAME "traffic"
49
50 #if HAVE_GETIFADDRS || defined(KERNEL_LINUX) || defined(HAVE_LIBKSTAT) || defined(HAVE_LIBSTATGRAB)
51 # define TRAFFIC_HAVE_READ 1
52 #else
53 # define TRAFFIC_HAVE_READ 0
54 #endif
55
56 #define BUFSIZE 512
57
58 static char *traffic_filename_template = "traffic-%s.rrd";
59
60 static char *ds_def[] =
61 {
62         "DS:incoming:COUNTER:"COLLECTD_HEARTBEAT":0:U",
63         "DS:outgoing:COUNTER:"COLLECTD_HEARTBEAT":0:U",
64         NULL
65 };
66 static int ds_num = 2;
67
68 #ifdef HAVE_LIBKSTAT
69 #define MAX_NUMIF 256
70 extern kstat_ctl_t *kc;
71 static kstat_t *ksp[MAX_NUMIF];
72 static int numif = 0;
73 #endif /* HAVE_LIBKSTAT */
74
75 static void traffic_init (void)
76 {
77 #if HAVE_GETIFADDRS
78         /* nothing */
79 /* #endif HAVE_GETIFADDRS */
80
81 #elif KERNEL_LINUX
82         /* nothing */
83 /* #endif KERNEL_LINUX */
84
85 #elif HAVE_LIBKSTAT
86         kstat_t *ksp_chain;
87         unsigned long long val;
88
89         numif = 0;
90
91         if (kc == NULL)
92                 return;
93
94         for (numif = 0, ksp_chain = kc->kc_chain;
95                         (numif < MAX_NUMIF) && (ksp_chain != NULL);
96                         ksp_chain = ksp_chain->ks_next)
97         {
98                 if (strncmp (ksp_chain->ks_class, "net", 3))
99                         continue;
100                 if (ksp_chain->ks_type != KSTAT_TYPE_NAMED)
101                         continue;
102                 if (kstat_read (kc, ksp_chain, NULL) == -1)
103                         continue;
104                 if ((val = get_kstat_value (ksp_chain, "obytes")) == -1LL)
105                         continue;
106                 ksp[numif++] = ksp_chain;
107         }
108 /* #endif HAVE_LIBKSTAT */
109
110 #elif HAVE_LIBSTATG
111         /* nothing */
112 #endif /* HAVE_LIBSTATG */
113
114         return;
115 }
116
117 static void traffic_write (char *host, char *inst, char *val)
118 {
119         char file[BUFSIZE];
120         int status;
121
122         status = snprintf (file, BUFSIZE, traffic_filename_template, inst);
123         if (status < 1)
124                 return;
125         else if (status >= BUFSIZE)
126                 return;
127
128         rrd_update_file (host, file, val, ds_def, ds_num);
129 }
130
131 #if TRAFFIC_HAVE_READ
132 static void traffic_submit (char *device,
133                 unsigned long long incoming,
134                 unsigned long long outgoing)
135 {
136         char buf[BUFSIZE];
137
138         if (snprintf (buf, BUFSIZE, "%u:%lld:%lld", (unsigned int) curtime, incoming, outgoing) >= BUFSIZE)
139                 return;
140
141         plugin_submit (MODULE_NAME, device, buf);
142 }
143
144 static void traffic_read (void)
145 {
146 #if HAVE_GETIFADDRS
147         struct ifaddrs *if_list;
148         struct ifaddrs *if_ptr;
149
150 #if HAVE_STRUCT_IF_DATA
151 #  define IFA_DATA if_data
152 #  define IFA_INCOMING ifi_ibytes
153 #  define IFA_OUTGOING ifi_obytes
154 #elif HAVE_STRUCT_NET_DEVICE_STATS
155 #  define IFA_DATA net_device_stats
156 #  define IFA_INCOMING rx_bytes
157 #  define IFA_OUTGOING tx_bytes
158 #else
159 #  error "No suitable type for `struct ifaddrs->ifa_data' found."
160 #endif
161
162         struct IFA_DATA *if_data;
163
164         if (getifaddrs (&if_list) != 0)
165                 return;
166
167         for (if_ptr = if_list; if_ptr != NULL; if_ptr = if_ptr->ifa_next)
168         {
169                 if ((if_data = (struct IFA_DATA *) if_ptr->ifa_data) == NULL)
170                         continue;
171
172                 traffic_submit (if_ptr->ifa_name,
173                                 if_data->IFA_INCOMING,
174                                 if_data->IFA_OUTGOING);
175         }
176
177         freeifaddrs (if_list);
178 /* #endif HAVE_GETIFADDRS */
179
180 #elif KERNEL_LINUX
181         FILE *fh;
182         char buffer[1024];
183         unsigned long long incoming, outgoing;
184         char *device;
185         
186         char *dummy;
187         char *fields[16];
188         int numfields;
189
190         if ((fh = fopen ("/proc/net/dev", "r")) == NULL)
191         {
192                 syslog (LOG_WARNING, "traffic: fopen: %s", strerror (errno));
193                 return;
194         }
195
196         while (fgets (buffer, 1024, fh) != NULL)
197         {
198                 if (buffer[6] != ':')
199                         continue;
200                 buffer[6] = '\0';
201
202                 device = buffer;
203                 while (device[0] == ' ')
204                         device++;
205
206                 if (device[0] == '\0')
207                         continue;
208                 
209                 dummy = buffer + 7;
210                 numfields = strsplit (dummy, fields, 16);
211
212                 if (numfields < 9)
213                         continue;
214
215                 incoming = atoll (fields[0]);
216                 outgoing = atoll (fields[8]);
217
218                 traffic_submit (device, incoming, outgoing);
219         }
220
221         fclose (fh);
222 /* #endif KERNEL_LINUX */
223
224 #elif defined(HAVE_LIBKSTAT)
225         int i;
226         unsigned long long incoming, outgoing;
227
228         if (kc == NULL)
229                 return;
230
231         for (i = 0; i < numif; i++)
232         {
233                 if (kstat_read (kc, ksp[i], NULL) == -1)
234                         continue;
235
236                 if ((incoming = get_kstat_value (ksp[i], "rbytes")) == -1LL)
237                         continue;
238                 if ((outgoing = get_kstat_value (ksp[i], "obytes")) == -1LL)
239                         continue;
240
241                 traffic_submit (ksp[i]->ks_name, incoming, outgoing);
242         }
243 /* #endif HAVE_LIBKSTAT */
244
245 #elif defined(HAVE_LIBSTATGRAB)
246         sg_network_io_stats *ios;
247         int i, num;
248
249         ios = sg_get_network_io_stats (&num);
250
251         for (i = 0; i < num; i++)
252                 traffic_submit (ios[i].interface_name, ios[i].rx, ios[i].tx);
253 #endif /* HAVE_LIBSTATGRAB */
254 }
255 #else
256 #define traffic_read NULL
257 #endif /* TRAFFIC_HAVE_READ */
258
259 void module_register (void)
260 {
261         plugin_register (MODULE_NAME, traffic_init, traffic_read, traffic_write);
262 }
263
264 #undef BUFSIZE
265 #undef MODULE_NAME