@cryptotaxi247 / netdata-1 / commits / 0c986ec9b

network interface speed, duplex, operstate #5989 (#7395)

* - Read and process /sys/class/net/XXXX/duplex and /sys/class/net/XXXX/operstate - Create custom variables duplex_state and operstate under the bandwidth chart - Map states to numeric values Duplex state (variable duplex_state) 0 = unknown 1 = half duplex 2 = full duplex Operstate status map (variable operstate) 0 = unknown 1 = notpresent 2 = down 3 = lowerlayerdown 4 = testing 5 = dormant 6 = up * - Fix array size element count! - Return int value - Fix casting warning * - Variable rename duplex_state to duplex * - Move the variable definition out of the loop

Stelios Fragkakis committed Jan 8, 2020 at 11:07 UTC 0c986ec9b1b0502f72e9051cab57a81bdb22398a
1 file changed +128 -4
collectors/proc.plugin/proc_net_dev.c
+128 -4
@@ -5,6 +5,21 @@
5 #define PLUGIN_PROC_MODULE_NETDEV_NAME "/proc/net/dev"
6 #define CONFIG_SECTION_PLUGIN_PROC_NETDEV "plugin:" PLUGIN_PROC_CONFIG_NAME ":" PLUGIN_PROC_MODULE_NETDEV_NAME
7
8 +// As defined in https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net
9 +const char *operstate_names[] = { "unknown", "notpresent", "down", "lowerlayerdown", "testing", "dormant", "up" };
10 +
11 +static inline int get_operstate(char *operstate)
12 +{
13 + int i;
14 +
15 + for (i = 0; i < (int) (sizeof(operstate_names) / sizeof(char *)); i++) {
16 + if (!strcmp(operstate, operstate_names[i])) {
17 + return i;
18 + }
19 + }
20 + return 0;
21 +}
22 +
23 // ----------------------------------------------------------------------------
24 // netdev list
25
@@ -67,6 +82,8 @@ static struct netdev {
82 kernel_uint_t tcarrier;
83 kernel_uint_t tcompressed;
84 kernel_uint_t speed;
85 + kernel_uint_t duplex;
86 + kernel_uint_t operstate;
87
88 // charts
89 RRDSET *st_bandwidth;
@@ -97,9 +114,18 @@ static struct netdev {
114 RRDDIM *rd_tcompressed;
115
116 usec_t speed_last_collected_usec;
117 + usec_t duplex_last_collected_usec;
118 + usec_t operstate_last_collected_usec;
119 +
120 char *filename_speed;
121 RRDSETVAR *chart_var_speed;
122
123 + char *filename_duplex;
124 + RRDSETVAR *chart_var_duplex;
125 +
126 + char *filename_operstate;
127 + RRDSETVAR *chart_var_operstate;
128 +
129 struct netdev *next;
130 } *netdev_root = NULL, *netdev_last_used = NULL;
131
@@ -169,11 +195,12 @@ static void netdev_free(struct netdev *d) {
195
196 freez((void *)d->name);
197 freez((void *)d->filename_speed);
198 + freez((void *)d->filename_duplex);
199 + freez((void *)d->filename_operstate);
200 freez((void *)d);
201 netdev_added--;
202 }
203
176 -
204 // ----------------------------------------------------------------------------
205 // netdev renames
206
@@ -439,9 +466,15 @@ int do_proc_net_dev(int update_every, usec_t dt) {
466 static SIMPLE_PATTERN *disabled_list = NULL;
467 static procfile *ff = NULL;
468 static int enable_new_interfaces = -1;
442 - static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1, do_events = -1;
443 - static char *path_to_sys_devices_virtual_net = NULL, *path_to_sys_class_net_speed = NULL, *proc_net_dev_filename = NULL;
469 + static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1,
470 + do_events = -1;
471 + static char *path_to_sys_devices_virtual_net = NULL, *path_to_sys_class_net_speed = NULL,
472 + *proc_net_dev_filename = NULL;
473 + static char *path_to_sys_class_net_duplex = NULL;
474 + static char *path_to_sys_class_net_operstate = NULL;
475 static long long int dt_to_refresh_speed = 0;
476 + static long long int dt_to_refresh_duplex = 0;
477 + static long long int dt_to_refresh_operstate = 0;
478
479 if(unlikely(enable_new_interfaces == -1)) {
480 char filename[FILENAME_MAX + 1];
@@ -455,6 +488,13 @@ int do_proc_net_dev(int update_every, usec_t dt) {
488 snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/speed");
489 path_to_sys_class_net_speed = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device speed", filename);
490
491 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/duplex");
492 + path_to_sys_class_net_duplex = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device duplex", filename);
493 +
494 + snprintfz(filename, FILENAME_MAX, "%s%s", netdata_configured_host_prefix, "/sys/class/net/%s/operstate");
495 + path_to_sys_class_net_operstate = config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "path to get net device operstate", filename);
496 +
497 +
498 enable_new_interfaces = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "enable new interfaces detected at runtime", CONFIG_BOOLEAN_AUTO);
499
500 do_bandwidth = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "bandwidth for all interfaces", CONFIG_BOOLEAN_AUTO);
@@ -468,7 +508,15 @@ int do_proc_net_dev(int update_every, usec_t dt) {
508 disabled_list = simple_pattern_create(config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "disable by default interfaces matching", "lo fireqos* *-ifb"), NULL, SIMPLE_PATTERN_EXACT);
509
510 dt_to_refresh_speed = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface speed every seconds", 10) * USEC_PER_SEC;
471 - if(dt_to_refresh_speed < 0) dt_to_refresh_speed = 0;
511 + dt_to_refresh_duplex = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface duplex every seconds", 10) * USEC_PER_SEC;
512 + dt_to_refresh_operstate = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface operstate every seconds", 10) * USEC_PER_SEC;
513 +
514 + if (dt_to_refresh_operstate < 0)
515 + dt_to_refresh_operstate = 0;
516 + if (dt_to_refresh_duplex < 0)
517 + dt_to_refresh_duplex = 0;
518 + if (dt_to_refresh_speed < 0)
519 + dt_to_refresh_speed = 0;
520 }
521
522 if(unlikely(!ff)) {
@@ -525,6 +573,12 @@ int do_proc_net_dev(int update_every, usec_t dt) {
573 // set the filename to get the interface speed
574 snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_speed, d->name);
575 d->filename_speed = strdupz(buffer);
576 +
577 + snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_duplex, d->name);
578 + d->filename_duplex = strdupz(buffer);
579 +
580 + snprintfz(buffer, FILENAME_MAX, path_to_sys_class_net_operstate, d->name);
581 + d->filename_operstate = strdupz(buffer);
582 }
583
584 snprintfz(buffer, FILENAME_MAX, "plugin:proc:/proc/net/dev:%s", d->name);
@@ -668,6 +722,76 @@ int do_proc_net_dev(int update_every, usec_t dt) {
722 }
723 }
724 }
725 +
726 + if (d->filename_duplex) {
727 + d->duplex_last_collected_usec += dt;
728 +
729 + if (unlikely(d->duplex_last_collected_usec >= (usec_t)dt_to_refresh_duplex)) {
730 + if (unlikely(!d->chart_var_duplex)) {
731 + d->chart_var_duplex = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "duplex");
732 + if (!d->chart_var_duplex) {
733 + error("Cannot create interface %s chart variable 'duplex'. Will not update the duplex status anymore.", d->name);
734 + freez(d->filename_duplex);
735 + d->filename_duplex = NULL;
736 + }
737 + }
738 +
739 + if (d->filename_duplex && d->chart_var_duplex) {
740 + char buffer[32 + 1];
741 +
742 + if (read_file(d->filename_duplex, buffer, 32)) {
743 + error("Cannot refresh interface %s duplex state by reading '%s'. I will stop updating it.", d->name, d->filename_duplex);
744 + freez(d->filename_duplex);
745 + d->filename_duplex = NULL;
746 + } else {
747 + // values can be unknown, half or full -- just check the first letter for speed
748 + if (buffer[0] == 'f')
749 + d->duplex = 2;
750 + else if (buffer[0] == 'h')
751 + d->duplex = 1;
752 + else
753 + d->duplex = 0;
754 +
755 + rrdsetvar_custom_chart_variable_set(d->chart_var_duplex, (calculated_number)d->duplex);
756 + d->duplex_last_collected_usec = 0;
757 + }
758 + }
759 + }
760 + }
761 +
762 + if (d->filename_operstate) {
763 + d->operstate_last_collected_usec += dt;
764 +
765 + if (unlikely(d->operstate_last_collected_usec >= (usec_t)dt_to_refresh_operstate)) {
766 + if (unlikely(!d->chart_var_operstate)) {
767 + d->chart_var_operstate = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "operstate");
768 + if (!d->chart_var_operstate) {
769 + error(
770 + "Cannot create interface %s chart variable 'operstate'. I will stop updating it.",
771 + d->name);
772 + freez(d->filename_operstate);
773 + d->filename_operstate = NULL;
774 + }
775 + }
776 +
777 + if (d->filename_operstate && d->chart_var_operstate) {
778 + char buffer[32 + 1], *trimmed_buffer;
779 +
780 + if (read_file(d->filename_operstate, buffer, 32)) {
781 + error(
782 + "Cannot refresh %s operstate by reading '%s'. Will not update its status anymore.",
783 + d->name, d->filename_operstate);
784 + freez(d->filename_operstate);
785 + d->filename_operstate = NULL;
786 + } else {
787 + trimmed_buffer = trim(buffer);
788 + d->operstate = get_operstate(trimmed_buffer);
789 + rrdsetvar_custom_chart_variable_set(d->chart_var_operstate, (calculated_number)d->operstate);
790 + d->operstate_last_collected_usec = 0;
791 + }
792 + }
793 + }
794 + }
795 }
796
797 // --------------------------------------------------------------------