summaryrefslogtreecommitdiffstats
path: root/collectors/proc.plugin/proc_net_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'collectors/proc.plugin/proc_net_dev.c')
-rw-r--r--collectors/proc.plugin/proc_net_dev.c162
1 files changed, 157 insertions, 5 deletions
diff --git a/collectors/proc.plugin/proc_net_dev.c b/collectors/proc.plugin/proc_net_dev.c
index 8d9751d1c..a90e3c3ee 100644
--- a/collectors/proc.plugin/proc_net_dev.c
+++ b/collectors/proc.plugin/proc_net_dev.c
@@ -5,6 +5,21 @@
#define PLUGIN_PROC_MODULE_NETDEV_NAME "/proc/net/dev"
#define CONFIG_SECTION_PLUGIN_PROC_NETDEV "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NETDEV_NAME
+// As defined in https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net
+const char *operstate_names[] = { "unknown", "notpresent", "down", "lowerlayerdown", "testing", "dormant", "up" };
+
+static inline int get_operstate(char *operstate)
+{
+ int i;
+
+ for (i = 0; i < (int) (sizeof(operstate_names) / sizeof(char *)); i++) {
+ if (!strcmp(operstate, operstate_names[i])) {
+ return i;
+ }
+ }
+ return 0;
+}
+
// ----------------------------------------------------------------------------
// netdev list
@@ -45,6 +60,8 @@ static struct netdev {
const char *chart_family;
+ struct label *chart_labels;
+
int flipped;
unsigned long priority;
@@ -67,6 +84,8 @@ static struct netdev {
kernel_uint_t tcarrier;
kernel_uint_t tcompressed;
kernel_uint_t speed;
+ kernel_uint_t duplex;
+ kernel_uint_t operstate;
// charts
RRDSET *st_bandwidth;
@@ -97,9 +116,18 @@ static struct netdev {
RRDDIM *rd_tcompressed;
usec_t speed_last_collected_usec;
+ usec_t duplex_last_collected_usec;
+ usec_t operstate_last_collected_usec;
+
char *filename_speed;
RRDSETVAR *chart_var_speed;
+ char *filename_duplex;
+ RRDSETVAR *chart_var_duplex;
+
+ char *filename_operstate;
+ RRDSETVAR *chart_var_operstate;
+
struct netdev *next;
} *netdev_root = NULL, *netdev_last_used = NULL;
@@ -166,14 +194,16 @@ static void netdev_free_chart_strings(struct netdev *d) {
static void netdev_free(struct netdev *d) {
netdev_charts_release(d);
netdev_free_chart_strings(d);
+ free_label_list(d->chart_labels);
freez((void *)d->name);
freez((void *)d->filename_speed);
+ freez((void *)d->filename_duplex);
+ freez((void *)d->filename_operstate);
freez((void *)d);
netdev_added--;
}
-
// ----------------------------------------------------------------------------
// netdev renames
@@ -184,6 +214,8 @@ static struct netdev_rename {
const char *container_device;
const char *container_name;
+ struct label *chart_labels;
+
int processed;
struct netdev_rename *next;
@@ -203,7 +235,9 @@ static struct netdev_rename *netdev_rename_find(const char *host_device, uint32_
}
// other threads can call this function to register a rename to a netdev
-void netdev_rename_device_add(const char *host_device, const char *container_device, const char *container_name) {
+void netdev_rename_device_add(
+ const char *host_device, const char *container_device, const char *container_name, struct label *labels)
+{
netdata_mutex_lock(&netdev_rename_mutex);
uint32_t hash = simple_hash(host_device);
@@ -213,6 +247,7 @@ void netdev_rename_device_add(const char *host_device, const char *container_dev
r->host_device = strdupz(host_device);
r->container_device = strdupz(container_device);
r->container_name = strdupz(container_name);
+ update_label_list(&r->chart_labels, labels);
r->hash = hash;
r->next = netdev_rename_root;
r->processed = 0;
@@ -227,6 +262,9 @@ void netdev_rename_device_add(const char *host_device, const char *container_dev
r->container_device = strdupz(container_device);
r->container_name = strdupz(container_name);
+
+ update_label_list(&r->chart_labels, labels);
+
r->processed = 0;
netdev_pending_renames++;
info("CGROUP: altered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
@@ -258,6 +296,7 @@ void netdev_rename_device_del(const char *host_device) {
freez((void *) r->host_device);
freez((void *) r->container_name);
freez((void *) r->container_device);
+ free_label_list(r->chart_labels);
freez((void *) r);
break;
}
@@ -307,6 +346,8 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
snprintfz(buffer, RRD_ID_LENGTH_MAX, "net %s", r->container_device);
d->chart_family = strdupz(buffer);
+ update_label_list(&d->chart_labels, r->chart_labels);
+
d->priority = NETDATA_CHART_PRIO_CGROUP_NET_IFACE;
d->flipped = 1;
}
@@ -439,9 +480,15 @@ int do_proc_net_dev(int update_every, usec_t dt) {
static SIMPLE_PATTERN *disabled_list = NULL;
static procfile *ff = NULL;
static int enable_new_interfaces = -1;
- static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
- static char *path_to_sys_devices_virtual_net = NULL, *path_to_sys_class_net_speed = NULL, *proc_net_dev_filename = NULL;
+ static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1,
+ do_events = -1;
+ static char *path_to_sys_devices_virtual_net = NULL, *path_to_sys_class_net_speed = NULL,
+ *proc_net_dev_filename = NULL;
+ static char *path_to_sys_class_net_duplex = NULL;
+ static char *path_to_sys_class_net_operstate = NULL;
static long long int dt_to_refresh_speed = 0;
+ static long long int dt_to_refresh_duplex = 0;
+ static long long int dt_to_refresh_operstate = 0;
if(unlikely(enable_new_interfaces == -1)) {
char filename[FILENAME_MAX + 1];
@@ -455,6 +502,13 @@ int do_proc_net_dev(int update_every, usec_t dt) {
snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/speed");
path_to_sys_class_net_speed = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device speed", filename);
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/duplex");
+ path_to_sys_class_net_duplex = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device duplex", filename);
+
+ snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/operstate");
+ path_to_sys_class_net_operstate = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device operstate", filename);
+
+
enable_new_interfaces = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
@@ -468,7 +522,15 @@ int do_proc_net_dev(int update_every, usec_t dt) {
disabled_list = simple_pattern_create(config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "disable by default interfaces matching", "lo fireqos* *-ifb"), NULL, SIMPLE_PATTERN_EXACT);
dt_to_refresh_speed = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface speed every seconds", 10) * USEC_PER_SEC;
- if(dt_to_refresh_speed < 0) dt_to_refresh_speed = 0;
+ dt_to_refresh_duplex = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface duplex every seconds", 10) * USEC_PER_SEC;
+ dt_to_refresh_operstate = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface operstate every seconds", 10) * USEC_PER_SEC;
+
+ if (dt_to_refresh_operstate < 0)
+ dt_to_refresh_operstate = 0;
+ if (dt_to_refresh_duplex < 0)
+ dt_to_refresh_duplex = 0;
+ if (dt_to_refresh_speed < 0)
+ dt_to_refresh_speed = 0;
}
if(unlikely(!ff)) {
@@ -525,6 +587,12 @@ int do_proc_net_dev(int update_every, usec_t dt) {
// set the filename to get the interface speed
snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_speed, d->name);
d->filename_speed = strdupz(buffer);
+
+ snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_duplex, d->name);
+ d->filename_duplex = strdupz(buffer);
+
+ snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_operstate, d->name);
+ d->filename_operstate = strdupz(buffer);
}
snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name);
@@ -623,6 +691,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
, RRDSET_TYPE_AREA
);
+ rrdset_update_labels(d->st_bandwidth, d->chart_labels);
+
d->rd_rbytes = rrddim_add(d->st_bandwidth, "received", NULL, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
d->rd_tbytes = rrddim_add(d->st_bandwidth, "sent", NULL, -8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
@@ -668,6 +738,76 @@ int do_proc_net_dev(int update_every, usec_t dt) {
}
}
}
+
+ if (d->filename_duplex) {
+ d->duplex_last_collected_usec += dt;
+
+ if (unlikely(d->duplex_last_collected_usec >= (usec_t)dt_to_refresh_duplex)) {
+ if (unlikely(!d->chart_var_duplex)) {
+ d->chart_var_duplex = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "duplex");
+ if (!d->chart_var_duplex) {
+ error("Cannot create interface %s chart variable 'duplex'. Will not update the duplex status anymore.", d->name);
+ freez(d->filename_duplex);
+ d->filename_duplex = NULL;
+ }
+ }
+
+ if (d->filename_duplex && d->chart_var_duplex) {
+ char buffer[32 + 1];
+
+ if (read_file(d->filename_duplex, buffer, 32)) {
+ error("Cannot refresh interface %s duplex state by reading '%s'. I will stop updating it.", d->name, d->filename_duplex);
+ freez(d->filename_duplex);
+ d->filename_duplex = NULL;
+ } else {
+ // values can be unknown, half or full -- just check the first letter for speed
+ if (buffer[0] == 'f')
+ d->duplex = 2;
+ else if (buffer[0] == 'h')
+ d->duplex = 1;
+ else
+ d->duplex = 0;
+
+ rrdsetvar_custom_chart_variable_set(d->chart_var_duplex, (calculated_number)d->duplex);
+ d->duplex_last_collected_usec = 0;
+ }
+ }
+ }
+ }
+
+ if (d->filename_operstate) {
+ d->operstate_last_collected_usec += dt;
+
+ if (unlikely(d->operstate_last_collected_usec >= (usec_t)dt_to_refresh_operstate)) {
+ if (unlikely(!d->chart_var_operstate)) {
+ d->chart_var_operstate = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "operstate");
+ if (!d->chart_var_operstate) {
+ error(
+ "Cannot create interface %s chart variable 'operstate'. I will stop updating it.",
+ d->name);
+ freez(d->filename_operstate);
+ d->filename_operstate = NULL;
+ }
+ }
+
+ if (d->filename_operstate && d->chart_var_operstate) {
+ char buffer[32 + 1], *trimmed_buffer;
+
+ if (read_file(d->filename_operstate, buffer, 32)) {
+ error(
+ "Cannot refresh %s operstate by reading '%s'. Will not update its status anymore.",
+ d->name, d->filename_operstate);
+ freez(d->filename_operstate);
+ d->filename_operstate = NULL;
+ } else {
+ trimmed_buffer = trim(buffer);
+ d->operstate = get_operstate(trimmed_buffer);
+ rrdsetvar_custom_chart_variable_set(d->chart_var_operstate, (calculated_number)d->operstate);
+ d->operstate_last_collected_usec = 0;
+ }
+ }
+ }
+ }
}
// --------------------------------------------------------------------
@@ -696,6 +836,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_packets, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_packets, d->chart_labels);
+
d->rd_rpackets = rrddim_add(d->st_packets, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tpackets = rrddim_add(d->st_packets, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_rmulticast = rrddim_add(d->st_packets, "multicast", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -742,6 +884,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_errors, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_errors, d->chart_labels);
+
d->rd_rerrors = rrddim_add(d->st_errors, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_terrors = rrddim_add(d->st_errors, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -786,6 +930,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_drops, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_drops, d->chart_labels);
+
d->rd_rdrops = rrddim_add(d->st_drops, "inbound", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tdrops = rrddim_add(d->st_drops, "outbound", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -830,6 +976,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_fifo, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_fifo, d->chart_labels);
+
d->rd_rfifo = rrddim_add(d->st_fifo, "receive", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tfifo = rrddim_add(d->st_fifo, "transmit", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -874,6 +1022,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_compressed, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_compressed, d->chart_labels);
+
d->rd_rcompressed = rrddim_add(d->st_compressed, "received", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tcompressed = rrddim_add(d->st_compressed, "sent", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
@@ -918,6 +1068,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrdset_flag_set(d->st_events, RRDSET_FLAG_DETAIL);
+ rrdset_update_labels(d->st_events, d->chart_labels);
+
d->rd_rframe = rrddim_add(d->st_events, "frames", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tcollisions = rrddim_add(d->st_events, "collisions", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
d->rd_tcarrier = rrddim_add(d->st_events, "carrier", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);