ethstat plugin: Collect performance statistics from NICs.
[collectd.git] / src / ethstat.c
1 /**
2  * collectd - src/ethstat.c
3  * Copyright (C) 2011       Cyril Feraudet
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  *   Cyril Feraudet <cyril at feraudet.com>
21  **/
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <math.h>
26 #include <time.h>
27 #include "collectd.h"
28 #include "common.h"
29 #include "plugin.h"
30 #include "configfile.h"
31 #include <sys/types.h>
32 #include <sys/types.h>
33 #include <sys/ioctl.h>
34 #include <sys/stat.h>
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <net/if.h>
39 #include <linux/sockios.h> 
40 #include "ethstat.h"
41
42 # if KERNEL_LINUX
43
44
45 static int ethstat_config (const char *key, const char *value)
46 {
47         if (strcasecmp (key, "Iface") == 0) {
48                 ifacelist[ifacenumber] = malloc(strlen(value) + 1);
49                 strcpy(ifacelist[ifacenumber++], value);
50                 INFO("ethstat: Registred iface %s", value);
51         }
52         return (0);
53 }
54
55
56 static void ethstat_submit_value (char *devname, char *counter, unsigned long long value)
57 {
58         value_t values[1];
59         value_list_t vl = VALUE_LIST_INIT;
60
61         values[0].counter = value;
62
63         vl.values = values;
64         vl.values_len = 1;
65         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
66         sstrncpy (vl.plugin, "ethstat", sizeof (vl.plugin));
67         sstrncpy (vl.plugin_instance, devname, sizeof (vl.plugin_instance));
68         sstrncpy (vl.type, "derive", sizeof (vl.type));
69         sstrncpy (vl.type_instance, counter, sizeof (vl.type_instance));
70
71         plugin_dispatch_values (&vl);
72 }
73
74
75 static int getstats(char *devname, struct ifreq *ifr) {
76         int fd;
77         struct ethtool_drvinfo drvinfo;
78         struct ethtool_gstrings *strings;
79         struct ethtool_stats *stats;
80         unsigned int n_stats, sz_str, sz_stats, i;
81         int err;
82
83
84         fd = socket(AF_INET, SOCK_DGRAM, 0);
85         if (fd < 0) {
86                 ERROR("ethstat - %s : Cannot get control socket", devname);
87                 return 1;
88         }
89
90         drvinfo.cmd = ETHTOOL_GDRVINFO;
91         ifr->ifr_data = (caddr_t)&drvinfo;
92         err = ioctl(fd, SIOCETHTOOL, ifr);
93         if (err < 0) {
94                 ERROR("ethstat - %s : Cannot get driver information", devname);
95                 return 1;
96         }
97
98
99         n_stats = drvinfo.n_stats;
100         if (n_stats < 1) {
101                 ERROR("ethstat - %s : No stats available", devname);
102                 return 1;
103         }
104
105         sz_str = n_stats * ETH_GSTRING_LEN;
106         sz_stats = n_stats * sizeof(u64);
107
108         strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
109         stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
110         if (!strings || !stats) {
111                 ERROR("ethstat - %s No memory available", devname);
112                 return 1;
113         }
114
115         strings->cmd = ETHTOOL_GSTRINGS;
116         strings->string_set = ETH_SS_STATS;
117         strings->len = n_stats;
118         ifr->ifr_data = (caddr_t) strings;
119         err = ioctl(fd, SIOCETHTOOL, ifr);
120         if (err < 0) {
121                 ERROR("ethstat - %s : Cannot get stats strings information", devname);
122                 free(strings);
123                 free(stats);
124                 return 96;
125         }
126
127         stats->cmd = ETHTOOL_GSTATS;
128         stats->n_stats = n_stats;
129         ifr->ifr_data = (caddr_t) stats;
130         err = ioctl(fd, SIOCETHTOOL, ifr);
131         if (err < 0) {
132                 ERROR("ethstat - %s : Cannot get stats information", devname);
133                 free(strings);
134                 free(stats);
135                 return 97;
136         }
137
138         for (i = 0; i < n_stats; i++) {
139                 DEBUG("ethstat - %s : %s: %llu",
140                         devname,
141                         &strings->data[i * ETH_GSTRING_LEN],
142                         stats->data[i]);
143                 ethstat_submit_value (
144                         devname,
145                         (char*)&strings->data[i * ETH_GSTRING_LEN],
146                         stats->data[i]);
147         }
148         free(strings);
149         free(stats);
150
151
152         return 0;
153 }
154
155
156 static int ethstat_read(void)
157 {
158         struct ifreq ifr;
159         int i;
160
161         for (i = 0 ; i < ifacenumber ; i++) {
162                 DEBUG("ethstat - Processing : %s\n", ifacelist[i]);
163                 memset(&ifr, 0, sizeof(ifr));
164                 strcpy(ifr.ifr_name, ifacelist[i]);
165                 getstats(ifacelist[i], &ifr);
166         }
167         return 0;
168 }
169
170 void module_register (void)
171 {
172         ifacelist = malloc(sizeof(char*));
173         plugin_register_config ("ethstat", ethstat_config,
174                         config_keys, config_keys_num);
175         plugin_register_read ("ethstat", ethstat_read);
176 }
177
178 #endif