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