2 * collectd - src/ethstat.c
3 * Copyright (C) 2011 Cyril Feraudet
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.
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.
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
20 * Cyril Feraudet <cyril at feraudet.com>
26 #include "configfile.h"
27 #include "utils_avltree.h"
30 # include <sys/ioctl.h>
35 #if HAVE_LINUX_SOCKIOS_H
36 # include <linux/sockios.h>
38 #if HAVE_LINUX_ETHTOOL_H
39 # include <linux/ethtool.h>
44 char type[DATA_MAX_NAME_LEN];
45 char type_instance[DATA_MAX_NAME_LEN];
47 typedef struct value_map_s value_map_t;
49 static char **interfaces = NULL;
50 static size_t interfaces_num = 0;
52 static c_avl_tree_t *value_map = NULL;
54 static int ethstat_add_interface (const oconfig_item_t *ci) /* {{{ */
59 tmp = realloc (interfaces,
60 sizeof (*interfaces) * (interfaces_num + 1));
65 status = cf_util_get_string (ci, interfaces + interfaces_num);
70 INFO("ethstat plugin: Registred interface %s",
71 interfaces[interfaces_num - 1]);
74 } /* }}} int ethstat_add_interface */
76 static int ethstat_add_map (const oconfig_item_t *ci) /* {{{ */
81 if ((ci->values_num < 2)
82 || (ci->values_num > 3)
83 || (ci->values[0].type != OCONFIG_TYPE_STRING)
84 || (ci->values[1].type != OCONFIG_TYPE_STRING)
85 || ((ci->values_num == 3)
86 && (ci->values[2].type != OCONFIG_TYPE_STRING)))
88 ERROR ("ethstat plugin: The %s option requires "
89 "two or three string arguments.", ci->key);
93 map = malloc (sizeof (*map));
96 ERROR ("ethstat plugin: malloc(3) failed.");
99 memset (map, 0, sizeof (*map));
101 sstrncpy (map->type, ci->values[1].value.string, sizeof (map->type));
102 if (ci->values_num == 2)
103 sstrncpy (map->type_instance, ci->values[2].value.string,
104 sizeof (map->type_instance));
106 if (value_map == NULL)
108 value_map = c_avl_create ((void *) strcmp);
109 if (value_map == NULL)
112 ERROR ("ethstat plugin: c_avl_create() failed.");
117 status = c_avl_insert (value_map,
118 /* key = */ ci->values[0].value.string,
124 ERROR ("ethstat plugin: Multiple mappings for \"%s\".",
125 ci->values[0].value.string);
127 ERROR ("ethstat plugin: c_avl_insert(\"%s\") failed.",
128 ci->values[0].value.string);
133 } /* }}} int ethstat_add_map */
135 static int ethstat_config (oconfig_item_t *ci) /* {{{ */
139 for (i = 0; i < ci->children_num; i++)
141 oconfig_item_t *child = ci->children + i;
143 if (strcasecmp ("Interface", child->key) == 0)
144 ethstat_add_interface (child);
145 else if (strcasecmp ("Map", child->key) == 0)
146 ethstat_add_map (child);
148 WARNING ("ethstat plugin: The config option \"%s\" is unknown.",
155 static void ethstat_submit_value (const char *device,
156 const char *type_instance, derive_t value)
159 value_list_t vl = VALUE_LIST_INIT;
160 value_map_t *map = NULL;
162 if (value_map != NULL)
163 c_avl_get (value_map, type_instance, (void *) &map);
165 values[0].derive = value;
169 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
170 sstrncpy (vl.plugin, "ethstat", sizeof (vl.plugin));
171 sstrncpy (vl.plugin_instance, device, sizeof (vl.plugin_instance));
174 sstrncpy (vl.type, map->type, sizeof (vl.type));
175 sstrncpy (vl.type_instance, map->type_instance,
176 sizeof (vl.type_instance));
180 sstrncpy (vl.type, "derive", sizeof (vl.type));
181 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
184 plugin_dispatch_values (&vl);
187 static int ethstat_read_interface (char *device)
191 struct ethtool_drvinfo drvinfo;
192 struct ethtool_gstrings *strings;
193 struct ethtool_stats *stats;
200 memset (&req, 0, sizeof (req));
201 sstrncpy(req.ifr_name, device, sizeof (req.ifr_name));
203 fd = socket(AF_INET, SOCK_DGRAM, /* protocol = */ 0);
207 ERROR("ethstat plugin: Failed to open control socket: %s",
208 sstrerror (errno, errbuf, sizeof (errbuf)));
212 memset (&drvinfo, 0, sizeof (drvinfo));
213 drvinfo.cmd = ETHTOOL_GDRVINFO;
214 req.ifr_data = (void *) &drvinfo;
215 status = ioctl (fd, SIOCETHTOOL, &req);
220 ERROR ("ethstat plugin: Failed to get driver information "
221 "from %s: %s", device,
222 sstrerror (errno, errbuf, sizeof (errbuf)));
226 n_stats = (size_t) drvinfo.n_stats;
230 ERROR("ethstat plugin: No stats available for %s", device);
234 strings_size = sizeof (struct ethtool_gstrings)
235 + (n_stats * ETH_GSTRING_LEN);
236 stats_size = sizeof (struct ethtool_stats)
237 + (n_stats * sizeof (uint64_t));
239 strings = malloc (strings_size);
240 stats = malloc (stats_size);
241 if ((strings == NULL) || (stats == NULL))
246 ERROR("ethstat plugin: malloc(3) failed.");
250 strings->cmd = ETHTOOL_GSTRINGS;
251 strings->string_set = ETH_SS_STATS;
252 strings->len = n_stats;
253 req.ifr_data = (void *) strings;
254 status = ioctl (fd, SIOCETHTOOL, &req);
261 ERROR ("ethstat plugin: Cannot get strings from %s: %s",
263 sstrerror (errno, errbuf, sizeof (errbuf)));
267 stats->cmd = ETHTOOL_GSTATS;
268 stats->n_stats = n_stats;
269 req.ifr_data = (void *) stats;
270 status = ioctl (fd, SIOCETHTOOL, &req);
277 ERROR("ethstat plugin: Reading statistics from %s failed: %s",
279 sstrerror (errno, errbuf, sizeof (errbuf)));
283 for (i = 0; i < n_stats; i++)
285 const char *stat_name;
287 stat_name = (void *) &strings->data[i * ETH_GSTRING_LEN],
288 DEBUG("ethstat plugin: device = \"%s\": %s = %"PRIu64,
290 (uint64_t) stats->data[i]);
291 ethstat_submit_value (device,
292 stat_name, (derive_t) stats->data[i]);
300 } /* }}} ethstat_read_interface */
302 static int ethstat_read(void)
306 for (i = 0; i < interfaces_num; i++)
307 ethstat_read_interface (interfaces[i]);
312 void module_register (void)
314 plugin_register_complex_config ("ethstat", ethstat_config);
315 plugin_register_read ("ethstat", ethstat_read);
318 /* vim: set sw=2 sts=2 et fdm=marker : */