summaryrefslogtreecommitdiffstats
path: root/collectors/proc.plugin/proc_net_dev.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:19:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-03-09 13:20:02 +0000
commit58daab21cd043e1dc37024a7f99b396788372918 (patch)
tree96771e43bb69f7c1c2b0b4f7374cb74d7866d0cb /collectors/proc.plugin/proc_net_dev.c
parentReleasing debian version 1.43.2-1. (diff)
downloadnetdata-58daab21cd043e1dc37024a7f99b396788372918.tar.xz
netdata-58daab21cd043e1dc37024a7f99b396788372918.zip
Merging upstream version 1.44.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'collectors/proc.plugin/proc_net_dev.c')
-rw-r--r--collectors/proc.plugin/proc_net_dev.c509
1 files changed, 463 insertions, 46 deletions
diff --git a/collectors/proc.plugin/proc_net_dev.c b/collectors/proc.plugin/proc_net_dev.c
index 8539c7725..b39f39683 100644
--- a/collectors/proc.plugin/proc_net_dev.c
+++ b/collectors/proc.plugin/proc_net_dev.c
@@ -5,16 +5,35 @@
#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
+#define RRDFUNCTIONS_NETDEV_HELP "View network interface statistics"
+
#define STATE_LENGTH_MAX 32
#define READ_RETRY_PERIOD 60 // seconds
+void cgroup_netdev_reset_all(void);
+void cgroup_netdev_release(const DICTIONARY_ITEM *link);
+const void *cgroup_netdev_dup(const DICTIONARY_ITEM *link);
+void cgroup_netdev_add_bandwidth(const DICTIONARY_ITEM *link, NETDATA_DOUBLE received, NETDATA_DOUBLE sent);
+
enum {
NETDEV_DUPLEX_UNKNOWN,
NETDEV_DUPLEX_HALF,
NETDEV_DUPLEX_FULL
};
+static const char *get_duplex_string(int duplex)
+{
+ switch (duplex) {
+ case NETDEV_DUPLEX_FULL:
+ return "full";
+ case NETDEV_DUPLEX_HALF:
+ return "half";
+ default:
+ return "unknown";
+ }
+}
+
enum {
NETDEV_OPERSTATE_UNKNOWN,
NETDEV_OPERSTATE_NOTPRESENT,
@@ -44,6 +63,26 @@ static inline int get_operstate(char *operstate)
return NETDEV_OPERSTATE_UNKNOWN;
}
+static const char *get_operstate_string(int operstate)
+{
+ switch (operstate) {
+ case NETDEV_OPERSTATE_UP:
+ return "up";
+ case NETDEV_OPERSTATE_DOWN:
+ return "down";
+ case NETDEV_OPERSTATE_NOTPRESENT:
+ return "notpresent";
+ case NETDEV_OPERSTATE_LOWERLAYERDOWN:
+ return "lowerlayerdown";
+ case NETDEV_OPERSTATE_TESTING:
+ return "testing";
+ case NETDEV_OPERSTATE_DORMANT:
+ return "dormant";
+ default:
+ return "unknown";
+ }
+}
+
// ----------------------------------------------------------------------------
// netdev list
@@ -58,6 +97,8 @@ static struct netdev {
int enabled;
int updated;
+ bool function_ready;
+
time_t discover_time;
int carrier_file_exists;
@@ -208,6 +249,8 @@ static struct netdev {
char *filename_carrier;
char *filename_mtu;
+ const DICTIONARY_ITEM *cgroup_netdev_link;
+
struct netdev *next;
} *netdev_root = NULL, *netdev_last_used = NULL;
@@ -216,18 +259,18 @@ static size_t netdev_added = 0, netdev_found = 0;
// ----------------------------------------------------------------------------
static void netdev_charts_release(struct netdev *d) {
- if(d->st_bandwidth) rrdset_is_obsolete(d->st_bandwidth);
- if(d->st_packets) rrdset_is_obsolete(d->st_packets);
- if(d->st_errors) rrdset_is_obsolete(d->st_errors);
- if(d->st_drops) rrdset_is_obsolete(d->st_drops);
- if(d->st_fifo) rrdset_is_obsolete(d->st_fifo);
- if(d->st_compressed) rrdset_is_obsolete(d->st_compressed);
- if(d->st_events) rrdset_is_obsolete(d->st_events);
- if(d->st_speed) rrdset_is_obsolete(d->st_speed);
- if(d->st_duplex) rrdset_is_obsolete(d->st_duplex);
- if(d->st_operstate) rrdset_is_obsolete(d->st_operstate);
- if(d->st_carrier) rrdset_is_obsolete(d->st_carrier);
- if(d->st_mtu) rrdset_is_obsolete(d->st_mtu);
+ if(d->st_bandwidth) rrdset_is_obsolete___safe_from_collector_thread(d->st_bandwidth);
+ if(d->st_packets) rrdset_is_obsolete___safe_from_collector_thread(d->st_packets);
+ if(d->st_errors) rrdset_is_obsolete___safe_from_collector_thread(d->st_errors);
+ if(d->st_drops) rrdset_is_obsolete___safe_from_collector_thread(d->st_drops);
+ if(d->st_fifo) rrdset_is_obsolete___safe_from_collector_thread(d->st_fifo);
+ if(d->st_compressed) rrdset_is_obsolete___safe_from_collector_thread(d->st_compressed);
+ if(d->st_events) rrdset_is_obsolete___safe_from_collector_thread(d->st_events);
+ if(d->st_speed) rrdset_is_obsolete___safe_from_collector_thread(d->st_speed);
+ if(d->st_duplex) rrdset_is_obsolete___safe_from_collector_thread(d->st_duplex);
+ if(d->st_operstate) rrdset_is_obsolete___safe_from_collector_thread(d->st_operstate);
+ if(d->st_carrier) rrdset_is_obsolete___safe_from_collector_thread(d->st_carrier);
+ if(d->st_mtu) rrdset_is_obsolete___safe_from_collector_thread(d->st_mtu);
d->st_bandwidth = NULL;
d->st_compressed = NULL;
@@ -326,6 +369,7 @@ static void netdev_free(struct netdev *d) {
netdev_charts_release(d);
netdev_free_chart_strings(d);
rrdlabels_destroy(d->chart_labels);
+ cgroup_netdev_release(d->cgroup_netdev_link);
freez((void *)d->name);
freez((void *)d->filename_speed);
@@ -352,11 +396,14 @@ static struct netdev_rename {
int processed;
+ const DICTIONARY_ITEM *cgroup_netdev_link;
+
struct netdev_rename *next;
} *netdev_rename_root = NULL;
static int netdev_pending_renames = 0;
static netdata_mutex_t netdev_rename_mutex = NETDATA_MUTEX_INITIALIZER;
+static netdata_mutex_t netdev_dev_mutex = NETDATA_MUTEX_INITIALIZER;
static struct netdev_rename *netdev_rename_find(const char *host_device, uint32_t hash) {
struct netdev_rename *r;
@@ -374,7 +421,8 @@ void netdev_rename_device_add(
const char *container_device,
const char *container_name,
RRDLABELS *labels,
- const char *ctx_prefix)
+ const char *ctx_prefix,
+ const DICTIONARY_ITEM *cgroup_netdev_link)
{
netdata_mutex_lock(&netdev_rename_mutex);
@@ -391,6 +439,8 @@ void netdev_rename_device_add(
r->hash = hash;
r->next = netdev_rename_root;
r->processed = 0;
+ r->cgroup_netdev_link = cgroup_netdev_link;
+
netdev_rename_root = r;
netdev_pending_renames++;
collector_info("CGROUP: registered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
@@ -406,6 +456,8 @@ void netdev_rename_device_add(
rrdlabels_migrate_to_these(r->chart_labels, labels);
r->processed = 0;
+ r->cgroup_netdev_link = cgroup_netdev_link;
+
netdev_pending_renames++;
collector_info("CGROUP: altered network interface rename for '%s' as '%s' under '%s'", r->host_device, r->container_device, r->container_name);
}
@@ -438,6 +490,7 @@ void netdev_rename_device_del(const char *host_device) {
freez((void *) r->container_device);
freez((void *) r->ctx_prefix);
rrdlabels_destroy(r->chart_labels);
+ cgroup_netdev_release(r->cgroup_netdev_link);
freez((void *) r);
break;
}
@@ -451,6 +504,7 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
netdev_charts_release(d);
netdev_free_chart_strings(d);
+ d->cgroup_netdev_link = cgroup_netdev_dup(r->cgroup_netdev_link);
char buffer[RRD_ID_LENGTH_MAX + 1];
@@ -521,6 +575,7 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
d->chart_family = strdupz("net");
rrdlabels_copy(d->chart_labels, r->chart_labels);
+ rrdlabels_add(d->chart_labels, "container_device", r->container_device, RRDLABEL_SRC_AUTO);
d->priority = NETDATA_CHART_PRIO_CGROUP_NET_IFACE;
d->flipped = 1;
@@ -554,6 +609,319 @@ static inline void netdev_rename_all_lock(void) {
}
// ----------------------------------------------------------------------------
+
+int netdev_function_net_interfaces(BUFFER *wb, int timeout __maybe_unused, const char *function __maybe_unused,
+ void *collector_data __maybe_unused,
+ rrd_function_result_callback_t result_cb, void *result_cb_data,
+ rrd_function_is_cancelled_cb_t is_cancelled_cb, void *is_cancelled_cb_data,
+ rrd_function_register_canceller_cb_t register_canceller_cb __maybe_unused,
+ void *register_canceller_cb_data __maybe_unused) {
+
+ buffer_flush(wb);
+ wb->content_type = CT_APPLICATION_JSON;
+ buffer_json_initialize(wb, "\"", "\"", 0, true, BUFFER_JSON_OPTIONS_DEFAULT);
+
+ buffer_json_member_add_string(wb, "hostname", rrdhost_hostname(localhost));
+ buffer_json_member_add_uint64(wb, "status", HTTP_RESP_OK);
+ buffer_json_member_add_string(wb, "type", "table");
+ buffer_json_member_add_time_t(wb, "update_every", 1);
+ buffer_json_member_add_string(wb, "help", RRDFUNCTIONS_NETDEV_HELP);
+ buffer_json_member_add_array(wb, "data");
+
+ double max_traffic_rx = 0.0;
+ double max_traffic_tx = 0.0;
+ double max_traffic = 0.0;
+ double max_packets_rx = 0.0;
+ double max_packets_tx = 0.0;
+ double max_mcast_rx = 0.0;
+ double max_drops_rx = 0.0;
+ double max_drops_tx = 0.0;
+
+ netdata_mutex_lock(&netdev_dev_mutex);
+
+ RRDDIM *rd = NULL;
+
+ for (struct netdev *d = netdev_root; d != netdev_last_used; d = d->next) {
+ if (unlikely(!d->function_ready))
+ continue;
+
+ buffer_json_add_array_item_array(wb);
+
+ buffer_json_add_array_item_string(wb, d->name);
+
+ buffer_json_add_array_item_string(wb, d->virtual ? "virtual" : "physical");
+ buffer_json_add_array_item_string(wb, d->flipped ? "cgroup" : "host");
+ buffer_json_add_array_item_string(wb, d->carrier == 1 ? "up" : "down");
+ buffer_json_add_array_item_string(wb, get_operstate_string(d->operstate));
+ buffer_json_add_array_item_string(wb, get_duplex_string(d->duplex));
+ buffer_json_add_array_item_double(wb, d->speed > 0 ? d->speed : NAN);
+ buffer_json_add_array_item_double(wb, d->mtu > 0 ? d->mtu : NAN);
+
+ rd = d->flipped ? d->rd_tbytes : d->rd_rbytes;
+ double traffic_rx = rrddim_get_last_stored_value(rd, &max_traffic_rx, 1000.0);
+ rd = d->flipped ? d->rd_rbytes : d->rd_tbytes;
+ double traffic_tx = rrddim_get_last_stored_value(rd, &max_traffic_tx, 1000.0);
+
+ rd = d->flipped ? d->rd_tpackets : d->rd_rpackets;
+ double packets_rx = rrddim_get_last_stored_value(rd, &max_packets_rx, 1000.0);
+ rd = d->flipped ? d->rd_rpackets : d->rd_tpackets;
+ double packets_tx = rrddim_get_last_stored_value(rd, &max_packets_tx, 1000.0);
+
+ double mcast_rx = rrddim_get_last_stored_value(d->rd_rmulticast, &max_mcast_rx, 1000.0);
+
+ rd = d->flipped ? d->rd_tdrops : d->rd_rdrops;
+ double drops_rx = rrddim_get_last_stored_value(rd, &max_drops_rx, 1.0);
+ rd = d->flipped ? d->rd_rdrops : d->rd_tdrops;
+ double drops_tx = rrddim_get_last_stored_value(rd, &max_drops_tx, 1.0);
+
+ // FIXME: "traffic" (total) is needed only for default_sorting
+ // can be removed when default_sorting will accept multiple columns (sum)
+ double traffic = NAN;
+ if (!isnan(traffic_rx) && !isnan(traffic_tx)) {
+ traffic = traffic_rx + traffic_tx;
+ max_traffic = MAX(max_traffic, traffic);
+ }
+
+
+ buffer_json_add_array_item_double(wb, traffic_rx);
+ buffer_json_add_array_item_double(wb, traffic_tx);
+ buffer_json_add_array_item_double(wb, traffic);
+ buffer_json_add_array_item_double(wb, packets_rx);
+ buffer_json_add_array_item_double(wb, packets_tx);
+ buffer_json_add_array_item_double(wb, mcast_rx);
+ buffer_json_add_array_item_double(wb, drops_rx);
+ buffer_json_add_array_item_double(wb, drops_tx);
+
+ buffer_json_add_array_item_object(wb);
+ {
+ buffer_json_member_add_string(wb, "severity", drops_rx + drops_tx > 0 ? "warning" : "normal");
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_array_close(wb);
+ }
+
+ netdata_mutex_unlock(&netdev_dev_mutex);
+
+ buffer_json_array_close(wb); // data
+ buffer_json_member_add_object(wb, "columns");
+ {
+ size_t field_id = 0;
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Interface", "Network Interface Name",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY | RRDF_FIELD_OPTS_STICKY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Type", "Network Interface Type",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "UsedBy", "Indicates whether the network interface is used by a cgroup or by the host system",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "PhState", "Current Physical State",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_VISIBLE | RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "OpState", "Current Operational State",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Duplex", "Current Duplex Mode",
+ RRDF_FIELD_TYPE_STRING, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NONE,
+ 0, NULL, NAN, RRDF_FIELD_SORT_ASCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Speed", "Current Link Speed",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
+ 0, "Mbit", NAN, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "MTU", "Maximum Transmission Unit",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
+ 0, "Octets", NAN, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
+ RRDF_FIELD_OPTS_UNIQUE_KEY,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "In", "Traffic Received",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Mbit", max_traffic_rx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Out", "Traffic Sent",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Mbit", max_traffic_tx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "Total", "Traffic Received and Sent",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Mbit", max_traffic, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_NONE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "PktsIn", "Received Packets",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Kpps", max_packets_rx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "PktsOut", "Sent Packets",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Kpps", max_packets_tx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "McastIn", "Multicast Received Packets",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Kpps", max_mcast_rx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_NONE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "DropsIn", "Dropped Inbound Packets",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Drops", max_drops_rx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(wb, field_id++, "DropsOut", "Dropped Outbound Packets",
+ RRDF_FIELD_TYPE_BAR_WITH_INTEGER, RRDF_FIELD_VISUAL_BAR, RRDF_FIELD_TRANSFORM_NUMBER,
+ 2, "Drops", max_drops_tx, RRDF_FIELD_SORT_DESCENDING, NULL,
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_VISIBLE,
+ NULL);
+
+ buffer_rrdf_table_add_field(
+ wb, field_id++,
+ "rowOptions", "rowOptions",
+ RRDF_FIELD_TYPE_NONE,
+ RRDR_FIELD_VISUAL_ROW_OPTIONS,
+ RRDF_FIELD_TRANSFORM_NONE, 0, NULL, NAN,
+ RRDF_FIELD_SORT_FIXED,
+ NULL,
+ RRDF_FIELD_SUMMARY_COUNT,
+ RRDF_FIELD_FILTER_NONE,
+ RRDF_FIELD_OPTS_DUMMY,
+ NULL);
+ }
+
+ buffer_json_object_close(wb); // columns
+ buffer_json_member_add_string(wb, "default_sort_column", "Total");
+
+ buffer_json_member_add_object(wb, "charts");
+ {
+ buffer_json_member_add_object(wb, "Traffic");
+ {
+ buffer_json_member_add_string(wb, "name", "Traffic");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "In");
+ buffer_json_add_array_item_string(wb, "Out");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_member_add_object(wb, "Packets");
+ {
+ buffer_json_member_add_string(wb, "name", "Packets");
+ buffer_json_member_add_string(wb, "type", "stacked-bar");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "PktsIn");
+ buffer_json_add_array_item_string(wb, "PktsOut");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+ }
+ buffer_json_object_close(wb); // charts
+
+ buffer_json_member_add_array(wb, "default_charts");
+ {
+ buffer_json_add_array_item_array(wb);
+ buffer_json_add_array_item_string(wb, "Traffic");
+ buffer_json_add_array_item_string(wb, "Interface");
+ buffer_json_array_close(wb);
+
+ buffer_json_add_array_item_array(wb);
+ buffer_json_add_array_item_string(wb, "Traffic");
+ buffer_json_add_array_item_string(wb, "Type");
+ buffer_json_array_close(wb);
+ }
+ buffer_json_array_close(wb);
+
+ buffer_json_member_add_object(wb, "group_by");
+ {
+ buffer_json_member_add_object(wb, "Type");
+ {
+ buffer_json_member_add_string(wb, "name", "Type");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "Type");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+
+ buffer_json_member_add_object(wb, "UsedBy");
+ {
+ buffer_json_member_add_string(wb, "name", "UsedBy");
+ buffer_json_member_add_array(wb, "columns");
+ {
+ buffer_json_add_array_item_string(wb, "UsedBy");
+ }
+ buffer_json_array_close(wb);
+ }
+ buffer_json_object_close(wb);
+ }
+ buffer_json_object_close(wb); // group_by
+
+ buffer_json_member_add_time_t(wb, "expires", now_realtime_sec() + 1);
+ buffer_json_finalize(wb);
+
+ int response = HTTP_RESP_OK;
+ if(is_cancelled_cb && is_cancelled_cb(is_cancelled_cb_data)) {
+ buffer_flush(wb);
+ response = HTTP_RESP_CLIENT_CLOSED_REQUEST;
+ }
+
+ if(result_cb)
+ result_cb(wb, response, result_cb_data);
+
+ return response;
+}
+
// netdev data collection
static void netdev_cleanup() {
@@ -615,6 +983,7 @@ static struct netdev *get_netdev(const char *name) {
d->hash = simple_hash(d->name);
d->len = strlen(d->name);
d->chart_labels = rrdlabels_create();
+ d->function_ready = false;
d->chart_type_net_bytes = strdupz("net");
d->chart_type_net_compressed = strdupz("net_compressed");
@@ -779,56 +1148,88 @@ int do_proc_net_dev(int update_every, usec_t dt) {
if(d->enabled)
d->enabled = !simple_pattern_matches(disabled_list, d->name);
- char buffer[FILENAME_MAX + 1];
+ char buf[FILENAME_MAX + 1];
+ snprintfz(buf, FILENAME_MAX, path_to_sys_devices_virtual_net, d->name);
- snprintfz(buffer, FILENAME_MAX, path_to_sys_devices_virtual_net, d->name);
- if (likely(access(buffer, R_OK) == 0)) {
- d->virtual = 1;
- rrdlabels_add(d->chart_labels, "interface_type", "virtual", RRDLABEL_SRC_AUTO);
- }
- else {
+ d->virtual = likely(access(buf, R_OK) == 0) ? 1 : 0;
+
+ // At least on Proxmox inside LXC: eth0 is virtual.
+ // Virtual interfaces are not taken into account in system.net calculations
+ if (inside_lxc_container && d->virtual && strncmp(d->name, "eth", 3) == 0)
d->virtual = 0;
+
+ if (d->virtual)
+ rrdlabels_add(d->chart_labels, "interface_type", "virtual", RRDLABEL_SRC_AUTO);
+ else
rrdlabels_add(d->chart_labels, "interface_type", "real", RRDLABEL_SRC_AUTO);
- }
+
rrdlabels_add(d->chart_labels, "device", name, RRDLABEL_SRC_AUTO);
if(likely(!d->virtual)) {
// 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(buf, FILENAME_MAX, path_to_sys_class_net_speed, d->name);
+ d->filename_speed = strdupz(buf);
- snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_duplex, d->name);
- d->filename_duplex = strdupz(buffer);
+ snprintfz(buf, FILENAME_MAX, path_to_sys_class_net_duplex, d->name);
+ d->filename_duplex = strdupz(buf);
}
- snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_operstate, d->name);
- d->filename_operstate = strdupz(buffer);
+ snprintfz(buf, FILENAME_MAX, path_to_sys_class_net_operstate, d->name);
+ d->filename_operstate = strdupz(buf);
- snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_carrier, d->name);
- d->filename_carrier = strdupz(buffer);
+ snprintfz(buf, FILENAME_MAX, path_to_sys_class_net_carrier, d->name);
+ d->filename_carrier = strdupz(buf);
- snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_mtu, d->name);
- d->filename_mtu = strdupz(buffer);
+ snprintfz(buf, FILENAME_MAX, path_to_sys_class_net_mtu, d->name);
+ d->filename_mtu = strdupz(buf);
- snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name);
- d->enabled = config_get_boolean_ondemand(buffer, "enabled", d->enabled);
- d->virtual = config_get_boolean(buffer, "virtual", d->virtual);
+ snprintfz(buf, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name);
+
+ if (config_exists(buf, "enabled"))
+ d->enabled = config_get_boolean_ondemand(buf, "enabled", d->enabled);
+ if (config_exists(buf, "virtual"))
+ d->virtual = config_get_boolean(buf, "virtual", d->virtual);
if(d->enabled == CONFIG_BOOLEAN_NO)
continue;
- d->do_bandwidth = config_get_boolean_ondemand(buffer, "bandwidth", do_bandwidth);
- d->do_packets = config_get_boolean_ondemand(buffer, "packets", do_packets);
- d->do_errors = config_get_boolean_ondemand(buffer, "errors", do_errors);
- d->do_drops = config_get_boolean_ondemand(buffer, "drops", do_drops);
- d->do_fifo = config_get_boolean_ondemand(buffer, "fifo", do_fifo);
- d->do_compressed = config_get_boolean_ondemand(buffer, "compressed", do_compressed);
- d->do_events = config_get_boolean_ondemand(buffer, "events", do_events);
- d->do_speed = config_get_boolean_ondemand(buffer, "speed", do_speed);
- d->do_duplex = config_get_boolean_ondemand(buffer, "duplex", do_duplex);
- d->do_operstate = config_get_boolean_ondemand(buffer, "operstate", do_operstate);
- d->do_carrier = config_get_boolean_ondemand(buffer, "carrier", do_carrier);
- d->do_mtu = config_get_boolean_ondemand(buffer, "mtu", do_mtu);
+ d->do_bandwidth = do_bandwidth;
+ d->do_packets = do_packets;
+ d->do_errors = do_errors;
+ d->do_drops = do_drops;
+ d->do_fifo = do_fifo;
+ d->do_compressed = do_compressed;
+ d->do_events = do_events;
+ d->do_speed = do_speed;
+ d->do_duplex = do_duplex;
+ d->do_operstate = do_operstate;
+ d->do_carrier = do_carrier;
+ d->do_mtu = do_mtu;
+
+ if (config_exists(buf, "bandwidth"))
+ d->do_bandwidth = config_get_boolean_ondemand(buf, "bandwidth", do_bandwidth);
+ if (config_exists(buf, "packets"))
+ d->do_packets = config_get_boolean_ondemand(buf, "packets", do_packets);
+ if (config_exists(buf, "errors"))
+ d->do_errors = config_get_boolean_ondemand(buf, "errors", do_errors);
+ if (config_exists(buf, "drops"))
+ d->do_drops = config_get_boolean_ondemand(buf, "drops", do_drops);
+ if (config_exists(buf, "fifo"))
+ d->do_fifo = config_get_boolean_ondemand(buf, "fifo", do_fifo);
+ if (config_exists(buf, "compressed"))
+ d->do_compressed = config_get_boolean_ondemand(buf, "compressed", do_compressed);
+ if (config_exists(buf, "events"))
+ d->do_events = config_get_boolean_ondemand(buf, "events", do_events);
+ if (config_exists(buf, "speed"))
+ d->do_speed = config_get_boolean_ondemand(buf, "speed", do_speed);
+ if (config_exists(buf, "duplex"))
+ d->do_duplex = config_get_boolean_ondemand(buf, "duplex", do_duplex);
+ if (config_exists(buf, "operstate"))
+ d->do_operstate = config_get_boolean_ondemand(buf, "operstate", do_operstate);
+ if (config_exists(buf, "carrier"))
+ d->do_carrier = config_get_boolean_ondemand(buf, "carrier", do_carrier);
+ if (config_exists(buf, "mtu"))
+ d->do_mtu = config_get_boolean_ondemand(buf, "mtu", do_mtu);
}
if(unlikely(!d->enabled))
@@ -1008,6 +1409,11 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrddim_set_by_pointer(d->st_bandwidth, d->rd_tbytes, (collected_number)d->tbytes);
rrdset_done(d->st_bandwidth);
+ if(d->cgroup_netdev_link)
+ cgroup_netdev_add_bandwidth(d->cgroup_netdev_link,
+ d->flipped ? d->rd_tbytes->collector.last_stored_value : -d->rd_rbytes->collector.last_stored_value,
+ d->flipped ? -d->rd_rbytes->collector.last_stored_value : d->rd_tbytes->collector.last_stored_value);
+
// update the interface speed
if(d->filename_speed) {
if(unlikely(!d->chart_var_speed)) {
@@ -1462,6 +1868,8 @@ int do_proc_net_dev(int update_every, usec_t dt) {
rrddim_set_by_pointer(d->st_events, d->rd_tcarrier, (collected_number)d->tcarrier);
rrdset_done(d->st_events);
}
+
+ d->function_ready = true;
}
if(do_bandwidth == CONFIG_BOOLEAN_YES || (do_bandwidth == CONFIG_BOOLEAN_AUTO &&
@@ -1518,6 +1926,9 @@ void *netdev_main(void *ptr)
netdata_thread_cleanup_push(netdev_main_cleanup, ptr);
+ rrd_collector_started();
+ rrd_function_add(localhost, NULL, "network-interfaces", 10, RRDFUNCTIONS_NETDEV_HELP, true, netdev_function_net_interfaces, NULL);
+
usec_t step = localhost->rrd_update_every * USEC_PER_SEC;
heartbeat_t hb;
heartbeat_init(&hb);
@@ -1529,11 +1940,17 @@ void *netdev_main(void *ptr)
if (unlikely(!service_running(SERVICE_COLLECTORS)))
break;
+ cgroup_netdev_reset_all();
+
worker_is_busy(0);
+
+ netdata_mutex_lock(&netdev_dev_mutex);
if(do_proc_net_dev(localhost->rrd_update_every, hb_dt))
break;
+ netdata_mutex_unlock(&netdev_dev_mutex);
}
netdata_thread_cleanup_pop(1);
+
return NULL;
}