diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:19:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-03-09 13:20:02 +0000 |
commit | 58daab21cd043e1dc37024a7f99b396788372918 (patch) | |
tree | 96771e43bb69f7c1c2b0b4f7374cb74d7866d0cb /collectors/proc.plugin/proc_net_dev.c | |
parent | Releasing debian version 1.43.2-1. (diff) | |
download | netdata-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.c | 509 |
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; } |