diff options
Diffstat (limited to 'collectors/proc.plugin/proc_net_wireless.c')
-rw-r--r-- | collectors/proc.plugin/proc_net_wireless.c | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/collectors/proc.plugin/proc_net_wireless.c b/collectors/proc.plugin/proc_net_wireless.c new file mode 100644 index 0000000..32a53c6 --- /dev/null +++ b/collectors/proc.plugin/proc_net_wireless.c @@ -0,0 +1,453 @@ +#include <stdbool.h> +#include "plugin_proc.h" + +#define PLUGIN_PROC_MODULE_NETWIRELESS_NAME "/proc/net/wireless" + +#define CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NETWIRELESS_NAME + + +static struct netwireless { + char *name; + uint32_t hash; + + //flags + bool configured; + struct timeval updated; + + int do_status; + int do_quality; + int do_discarded_packets; + int do_missed_beacon; + + // Data collected + // status + kernel_uint_t status; + + // Quality + calculated_number link; + calculated_number level; + calculated_number noise; + + // Discarded packets + kernel_uint_t nwid; + kernel_uint_t crypt; + kernel_uint_t frag; + kernel_uint_t retry; + kernel_uint_t misc; + + // missed beacon + kernel_uint_t missed_beacon; + + const char *chart_id_net_status; + const char *chart_id_net_link; + const char *chart_id_net_level; + const char *chart_id_net_noise; + const char *chart_id_net_discarded_packets; + const char *chart_id_net_missed_beacon; + + const char *chart_family; + + // charts + // satus + RRDSET *st_status; + + // Quality + RRDSET *st_link; + RRDSET *st_level; + RRDSET *st_noise; + + // Discarded Packets + RRDSET *st_discarded_packets; + // Missed beacon + RRDSET *st_missed_beacon; + + // Dimensions + // status + RRDDIM *rd_status; + + // Quality + RRDDIM *rd_link; + RRDDIM *rd_level; + RRDDIM *rd_noise; + + // Discarded packets + RRDDIM *rd_nwid; + RRDDIM *rd_crypt; + RRDDIM *rd_frag; + RRDDIM *rd_retry; + RRDDIM *rd_misc; + + // missed beacon + RRDDIM *rd_missed_beacon; + + struct netwireless *next; +} *netwireless_root = NULL; + +static void netwireless_free_st(struct netwireless *wireless_dev) +{ + if (wireless_dev->st_status) rrdset_is_obsolete(wireless_dev->st_status); + if (wireless_dev->st_link) rrdset_is_obsolete(wireless_dev->st_link); + if (wireless_dev->st_level) rrdset_is_obsolete(wireless_dev->st_level); + if (wireless_dev->st_noise) rrdset_is_obsolete(wireless_dev->st_noise); + if (wireless_dev->st_discarded_packets) rrdset_is_obsolete(wireless_dev->st_discarded_packets); + if (wireless_dev->st_missed_beacon) rrdset_is_obsolete(wireless_dev->st_missed_beacon); + + wireless_dev->st_status = NULL; + wireless_dev->st_link = NULL; + wireless_dev->st_level = NULL; + wireless_dev->st_noise = NULL; + wireless_dev->st_discarded_packets = NULL; + wireless_dev->st_missed_beacon = NULL; +} + +static void netwireless_free(struct netwireless *wireless_dev) +{ + wireless_dev->next = NULL; + freez((void *)wireless_dev->name); + netwireless_free_st(wireless_dev); + freez((void *)wireless_dev->chart_id_net_status); + freez((void *)wireless_dev->chart_id_net_link); + freez((void *)wireless_dev->chart_id_net_level); + freez((void *)wireless_dev->chart_id_net_noise); + freez((void *)wireless_dev->chart_id_net_discarded_packets); + freez((void *)wireless_dev->chart_id_net_missed_beacon); + + freez((void *)wireless_dev); +} + +static void netwireless_cleanup(struct timeval *timestamp) +{ + struct netwireless *previous = NULL; + struct netwireless *current; + // search it, from begining to the end + for (current = netwireless_root; current;) { + + if (timercmp(¤t->updated, timestamp, <)) { + struct netwireless *to_free = current; + current = current->next; + netwireless_free(to_free); + + if (previous) { + previous->next = current; + } else { + netwireless_root = current; + } + } else { + previous = current; + current = current->next; + } + } +} + +// finds an existing interface or creates a new entry +static struct netwireless *find_or_create_wireless(const char *name) +{ + struct netwireless *wireless; + uint32_t hash = simple_hash(name); + + // search it, from begining to the end + for (wireless = netwireless_root ; wireless ; wireless = wireless->next) { + if (unlikely(hash == wireless->hash && !strcmp(name, wireless->name))) { + return wireless; + } + } + + // create a new one + wireless = callocz(1, sizeof(struct netwireless)); + wireless->name = strdupz(name); + wireless->hash = hash; + + // link it to the end + if (netwireless_root) { + struct netwireless *last_node; + for (last_node = netwireless_root; last_node->next ; last_node = last_node->next); + + last_node->next = wireless; + } else + netwireless_root = wireless; + + return wireless; +} + +static void configure_device(int do_status, int do_quality, int do_discarded_packets, int do_missed, + struct netwireless *wireless_dev) { + wireless_dev->do_status = do_status; + wireless_dev->do_quality = do_quality; + wireless_dev->do_discarded_packets = do_discarded_packets; + wireless_dev->do_missed_beacon = do_missed; + wireless_dev->configured = true; + + char buffer[RRD_ID_LENGTH_MAX + 1]; + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_status", wireless_dev->name); + wireless_dev->chart_id_net_status = strdupz(buffer); + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_link_quality", wireless_dev->name); + wireless_dev->chart_id_net_link = strdupz(buffer); + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_signal_level", wireless_dev->name); + wireless_dev->chart_id_net_level = strdupz(buffer); + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_noise_level", wireless_dev->name); + wireless_dev->chart_id_net_noise = strdupz(buffer); + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_discarded_packets", wireless_dev->name); + wireless_dev->chart_id_net_discarded_packets = strdupz(buffer); + + snprintfz(buffer, RRD_ID_LENGTH_MAX, "%s_missed_beacon", wireless_dev->name); + wireless_dev->chart_id_net_missed_beacon = strdupz(buffer); +} + +int do_proc_net_wireless(int update_every, usec_t dt) +{ + UNUSED(dt); + static procfile *ff = NULL; + static int do_status, do_quality = -1, do_discarded_packets, do_beacon; + static char *proc_net_wireless_filename = NULL; + + if (unlikely(do_quality == -1)) { + char filename[FILENAME_MAX + 1]; + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/proc/net/wireless"); + + proc_net_wireless_filename = config_get(CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS,"filename to monitor", + filename); + + do_status = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS, + "status for all interfaces", CONFIG_BOOLEAN_AUTO); + + do_quality = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS, + "quality for all interfaces", CONFIG_BOOLEAN_AUTO); + + do_discarded_packets = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS, + "discarded packets for all interfaces", + CONFIG_BOOLEAN_AUTO); + + do_beacon = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETWIRELESS, + "missed beacon for all interface", CONFIG_BOOLEAN_AUTO); + } + + if (unlikely(!ff)) { + ff = procfile_open(proc_net_wireless_filename, " \t,|", PROCFILE_FLAG_DEFAULT); + if (unlikely(!ff)) return 1; + } + + ff = procfile_readall(ff); + if (unlikely(!ff)) return 1; + + size_t lines = procfile_lines(ff); + struct timeval timestamp; + size_t l; + gettimeofday(×tamp, NULL); + for (l = 2; l < lines; l++) { + if (unlikely(procfile_linewords(ff, l) < 11)) continue; + + char *name = procfile_lineword(ff, l, 0); + size_t len = strlen(name); + if (name[len - 1] == ':') name[len - 1] = '\0'; + + struct netwireless *wireless_dev = find_or_create_wireless(name); + + if (unlikely(!wireless_dev->configured)) { + configure_device(do_status, do_quality, do_discarded_packets, do_beacon, wireless_dev); + } + + if (likely(do_status != CONFIG_BOOLEAN_NO)) { + wireless_dev->status = str2kernel_uint_t(procfile_lineword(ff, l, 1)); + + if (unlikely(!wireless_dev->st_status)) { + wireless_dev->st_status = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_status, + NULL, + wireless_dev->name, + "wireless.status", + "Internal status reported by interface.", + "status", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE, + update_every, + RRDSET_TYPE_LINE); + rrdset_flag_set(wireless_dev->st_status, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_status = rrddim_add(wireless_dev->st_status, "status", NULL, 1, + 1, RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(wireless_dev->st_status); + } + + rrddim_set_by_pointer(wireless_dev->st_status, wireless_dev->rd_status, + (collected_number)wireless_dev->status); + rrdset_done(wireless_dev->st_status); + } + + if (likely(do_quality != CONFIG_BOOLEAN_NO)) { + wireless_dev->link = str2ld(procfile_lineword(ff, l, 2), NULL); + wireless_dev->level = str2ld(procfile_lineword(ff, l, 3), NULL); + wireless_dev->noise = str2ld(procfile_lineword(ff, l, 4), NULL); + + if (unlikely(!wireless_dev->st_link)) { + wireless_dev->st_link = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_link, + NULL, + wireless_dev->name, + "wireless.link_quality", + "Overall quality of the link. This is an aggregate value, and depends on the driver and hardware.", + "value", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE + 1, + update_every, + RRDSET_TYPE_LINE); + rrdset_flag_set(wireless_dev->st_link, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_link = rrddim_add(wireless_dev->st_link, "link_quality", NULL, 1, 1, + RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(wireless_dev->st_link); + } + + if (unlikely(!wireless_dev->st_level)) { + wireless_dev->st_level = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_level, + NULL, + wireless_dev->name, + "wireless.signal_level", + "The signal level is the wireless signal power level received by the wireless client. The closer the value is to 0, the stronger the signal.", + "dBm", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE + 2, + update_every, + RRDSET_TYPE_LINE); + rrdset_flag_set(wireless_dev->st_level, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_level = rrddim_add(wireless_dev->st_level, "signal_level", NULL, 1, 1, + RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(wireless_dev->st_level); + } + + if (unlikely(!wireless_dev->st_noise)) { + wireless_dev->st_noise = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_noise, + NULL, + wireless_dev->name, + "wireless.noise_level", + "The noise level indicates the amount of background noise in your environment. The closer the value to 0, the greater the noise level.", + "dBm", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE + 3, + update_every, + RRDSET_TYPE_LINE); + rrdset_flag_set(wireless_dev->st_noise, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_noise = rrddim_add(wireless_dev->st_noise, "noise_level", NULL, 1, 1, + RRD_ALGORITHM_ABSOLUTE); + } else { + rrdset_next(wireless_dev->st_noise); + } + + rrddim_set_by_pointer(wireless_dev->st_link, wireless_dev->rd_link, + (collected_number)wireless_dev->link); + rrdset_done(wireless_dev->st_link); + + rrddim_set_by_pointer(wireless_dev->st_level, wireless_dev->rd_level, + (collected_number)wireless_dev->level); + rrdset_done(wireless_dev->st_level); + + rrddim_set_by_pointer(wireless_dev->st_noise, wireless_dev->rd_noise, + (collected_number)wireless_dev->noise); + rrdset_done(wireless_dev->st_noise); + } + + if (likely(do_discarded_packets)) { + wireless_dev->nwid = str2kernel_uint_t(procfile_lineword(ff, l, 5)); + wireless_dev->crypt = str2kernel_uint_t(procfile_lineword(ff, l, 6)); + wireless_dev->frag = str2kernel_uint_t(procfile_lineword(ff, l, 7)); + wireless_dev->retry = str2kernel_uint_t(procfile_lineword(ff, l, 8)); + wireless_dev->misc = str2kernel_uint_t(procfile_lineword(ff, l, 9)); + + if (unlikely(!wireless_dev->st_discarded_packets)) { + wireless_dev->st_discarded_packets = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_discarded_packets, + NULL, + wireless_dev->name, + "wireless.discarded_packets", + "Packet discarded in the wireless adapter due to \"wireless\" specific problems.", + "packets/s", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE + 4, + update_every, + RRDSET_TYPE_LINE); + + rrdset_flag_set(wireless_dev->st_discarded_packets, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_nwid = rrddim_add(wireless_dev->st_discarded_packets, "nwid", NULL, 1, + 1, RRD_ALGORITHM_INCREMENTAL); + wireless_dev->rd_crypt = rrddim_add(wireless_dev->st_discarded_packets, "crypt", NULL, 1, + 1, RRD_ALGORITHM_INCREMENTAL); + wireless_dev->rd_frag = rrddim_add(wireless_dev->st_discarded_packets, "frag", NULL, 1, + 1, RRD_ALGORITHM_INCREMENTAL); + wireless_dev->rd_retry = rrddim_add(wireless_dev->st_discarded_packets, "retry", NULL, 1, + 1, RRD_ALGORITHM_INCREMENTAL); + wireless_dev->rd_misc = rrddim_add(wireless_dev->st_discarded_packets, "misc", NULL, 1, + 1, RRD_ALGORITHM_INCREMENTAL); + } else { + rrdset_next(wireless_dev->st_discarded_packets); + } + + rrddim_set_by_pointer(wireless_dev->st_discarded_packets, wireless_dev->rd_nwid, + (collected_number)wireless_dev->nwid); + + rrddim_set_by_pointer(wireless_dev->st_discarded_packets, wireless_dev->rd_crypt, + (collected_number)wireless_dev->crypt); + + rrddim_set_by_pointer(wireless_dev->st_discarded_packets, wireless_dev->rd_frag, + (collected_number)wireless_dev->frag); + + rrddim_set_by_pointer(wireless_dev->st_discarded_packets, wireless_dev->rd_retry, + (collected_number)wireless_dev->retry); + + rrddim_set_by_pointer(wireless_dev->st_discarded_packets, wireless_dev->rd_misc, + (collected_number)wireless_dev->misc); + + rrdset_done(wireless_dev->st_discarded_packets); + } + + if (likely(do_beacon)) { + wireless_dev->missed_beacon = str2kernel_uint_t(procfile_lineword(ff, l, 10)); + + if (unlikely(!wireless_dev->st_missed_beacon)) { + wireless_dev->st_missed_beacon = rrdset_create_localhost("wireless", + wireless_dev->chart_id_net_missed_beacon, + NULL, + wireless_dev->name, + "wireless.missed_beacons", + "Number of missed beacons.", + "frames/s", + PLUGIN_PROC_NAME, + PLUGIN_PROC_MODULE_NETWIRELESS_NAME, + NETDATA_CHART_PRIO_WIRELESS_IFACE + 5, + update_every, + RRDSET_TYPE_LINE); + rrdset_flag_set(wireless_dev->st_missed_beacon, RRDSET_FLAG_DETAIL); + + wireless_dev->rd_missed_beacon = rrddim_add(wireless_dev->st_missed_beacon, "missed_beacons", + NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL); + } else { + rrdset_next(wireless_dev->st_missed_beacon); + } + + rrddim_set_by_pointer(wireless_dev->st_missed_beacon, wireless_dev->rd_missed_beacon, + (collected_number)wireless_dev->missed_beacon); + rrdset_done(wireless_dev->st_missed_beacon); + } + + wireless_dev->updated = timestamp; + } + + netwireless_cleanup(×tamp); + return 0; +} |