@cryptotaxi247 / netdata-1 / commits / 720bcf495

Move network interface speed, duplex, and operstate variables to charts (#10740)

Vladimir Kobal committed Mar 10, 2021 at 21:02 UTC 720bcf495c9679725479e0bd38c2b2b828be8e6a
3 files changed +193 -108
collectors/proc.plugin/proc_net_dev.c
+189 -105
@@ -5,6 +5,8 @@
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 +#define STATE_LENGTH_MAX 32
9 +
10 // As defined in https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-net
11 const char *operstate_names[] = { "unknown", "notpresent", "down", "lowerlayerdown", "testing", "dormant", "up" };
12
@@ -41,6 +43,9 @@ static struct netdev {
43 int do_fifo;
44 int do_compressed;
45 int do_events;
46 + int do_speed;
47 + int do_duplex;
48 + int do_operstate;
49
50 const char *chart_type_net_bytes;
51 const char *chart_type_net_packets;
@@ -49,6 +54,9 @@ static struct netdev {
54 const char *chart_type_net_events;
55 const char *chart_type_net_drops;
56 const char *chart_type_net_compressed;
57 + const char *chart_type_net_speed;
58 + const char *chart_type_net_duplex;
59 + const char *chart_type_net_operstate;
60
61 const char *chart_id_net_bytes;
62 const char *chart_id_net_packets;
@@ -57,6 +65,9 @@ static struct netdev {
65 const char *chart_id_net_events;
66 const char *chart_id_net_drops;
67 const char *chart_id_net_compressed;
68 + const char *chart_id_net_speed;
69 + const char *chart_id_net_duplex;
70 + const char *chart_id_net_operstate;
71
72 const char *chart_family;
73
@@ -95,6 +106,9 @@ static struct netdev {
106 RRDSET *st_fifo;
107 RRDSET *st_compressed;
108 RRDSET *st_events;
109 + RRDSET *st_speed;
110 + RRDSET *st_duplex;
111 + RRDSET *st_operstate;
112
113 // dimensions
114 RRDDIM *rd_rbytes;
@@ -115,18 +129,16 @@ static struct netdev {
129 RRDDIM *rd_tcarrier;
130 RRDDIM *rd_tcompressed;
131
118 - usec_t speed_last_collected_usec;
119 - usec_t duplex_last_collected_usec;
120 - usec_t operstate_last_collected_usec;
132 + RRDDIM *rd_speed;
133 + RRDDIM *rd_duplex;
134 + RRDDIM *rd_operstate;
135
136 char *filename_speed;
137 RRDSETVAR *chart_var_speed;
138
139 char *filename_duplex;
126 - RRDSETVAR *chart_var_duplex;
140
141 char *filename_operstate;
129 - RRDSETVAR *chart_var_operstate;
142
143 struct netdev *next;
144 } *netdev_root = NULL, *netdev_last_used = NULL;
@@ -143,6 +155,9 @@ static void netdev_charts_release(struct netdev *d) {
155 if(d->st_fifo) rrdset_is_obsolete(d->st_fifo);
156 if(d->st_compressed) rrdset_is_obsolete(d->st_compressed);
157 if(d->st_events) rrdset_is_obsolete(d->st_events);
158 + if(d->st_speed) rrdset_is_obsolete(d->st_speed);
159 + if(d->st_duplex) rrdset_is_obsolete(d->st_duplex);
160 + if(d->st_operstate) rrdset_is_obsolete(d->st_operstate);
161
162 d->st_bandwidth = NULL;
163 d->st_compressed = NULL;
@@ -151,6 +166,9 @@ static void netdev_charts_release(struct netdev *d) {
166 d->st_events = NULL;
167 d->st_fifo = NULL;
168 d->st_packets = NULL;
169 + d->st_speed = NULL;
170 + d->st_duplex = NULL;
171 + d->st_operstate = NULL;
172
173 d->rd_rbytes = NULL;
174 d->rd_rpackets = NULL;
@@ -170,9 +188,11 @@ static void netdev_charts_release(struct netdev *d) {
188 d->rd_tcarrier = NULL;
189 d->rd_tcompressed = NULL;
190
191 + d->rd_speed = NULL;
192 + d->rd_duplex = NULL;
193 + d->rd_operstate = NULL;
194 +
195 d->chart_var_speed = NULL;
174 - d->chart_var_duplex = NULL;
175 - d->chart_var_operstate = NULL;
196 }
197
198 static void netdev_free_chart_strings(struct netdev *d) {
@@ -183,6 +203,9 @@ static void netdev_free_chart_strings(struct netdev *d) {
203 freez((void *)d->chart_type_net_events);
204 freez((void *)d->chart_type_net_fifo);
205 freez((void *)d->chart_type_net_packets);
206 + freez((void *)d->chart_type_net_speed);
207 + freez((void *)d->chart_type_net_duplex);
208 + freez((void *)d->chart_type_net_operstate);
209
210 freez((void *)d->chart_id_net_bytes);
211 freez((void *)d->chart_id_net_compressed);
@@ -191,6 +214,9 @@ static void netdev_free_chart_strings(struct netdev *d) {
214 freez((void *)d->chart_id_net_events);
215 freez((void *)d->chart_id_net_fifo);
216 freez((void *)d->chart_id_net_packets);
217 + freez((void *)d->chart_id_net_speed);
218 + freez((void *)d->chart_id_net_duplex);
219 + freez((void *)d->chart_id_net_operstate);
220
221 freez((void *)d->chart_family);
222 }
@@ -325,6 +351,9 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
351 d->chart_type_net_events = strdupz(buffer);
352 d->chart_type_net_fifo = strdupz(buffer);
353 d->chart_type_net_packets = strdupz(buffer);
354 + d->chart_type_net_speed = strdupz(buffer);
355 + d->chart_type_net_duplex = strdupz(buffer);
356 + d->chart_type_net_operstate = strdupz(buffer);
357
358 snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_%s", r->container_device);
359 d->chart_id_net_bytes = strdupz(buffer);
@@ -347,6 +376,15 @@ static inline void netdev_rename_cgroup(struct netdev *d, struct netdev_rename *
376 snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_packets_%s", r->container_device);
377 d->chart_id_net_packets = strdupz(buffer);
378
379 + snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_speed_%s", r->container_device);
380 + d->chart_id_net_speed = strdupz(buffer);
381 +
382 + snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_duplex_%s", r->container_device);
383 + d->chart_id_net_duplex = strdupz(buffer);
384 +
385 + snprintfz(buffer, RRD_ID_LENGTH_MAX, "net_operstate_%s", r->container_device);
386 + d->chart_id_net_operstate = strdupz(buffer);
387 +
388 snprintfz(buffer, RRD_ID_LENGTH_MAX, "net %s", r->container_device);
389 d->chart_family = strdupz(buffer);
390
@@ -451,6 +489,9 @@ static struct netdev *get_netdev(const char *name) {
489 d->chart_type_net_events = strdupz("net_events");
490 d->chart_type_net_fifo = strdupz("net_fifo");
491 d->chart_type_net_packets = strdupz("net_packets");
492 + d->chart_type_net_speed = strdupz("net_speed");
493 + d->chart_type_net_duplex = strdupz("net_duplex");
494 + d->chart_type_net_operstate = strdupz("net_operstate");
495
496 d->chart_id_net_bytes = strdupz(d->name);
497 d->chart_id_net_compressed = strdupz(d->name);
@@ -459,6 +500,9 @@ static struct netdev *get_netdev(const char *name) {
500 d->chart_id_net_events = strdupz(d->name);
501 d->chart_id_net_fifo = strdupz(d->name);
502 d->chart_id_net_packets = strdupz(d->name);
503 + d->chart_id_net_speed = strdupz(d->name);
504 + d->chart_id_net_duplex = strdupz(d->name);
505 + d->chart_id_net_operstate = strdupz(d->name);
506
507 d->chart_family = strdupz(d->name);
508 d->priority = NETDATA_CHART_PRIO_FIRST_NET_IFACE;
@@ -485,14 +529,11 @@ int do_proc_net_dev(int update_every, usec_t dt) {
529 static procfile *ff = NULL;
530 static int enable_new_interfaces = -1;
531 static int do_bandwidth = -1, do_packets = -1, do_errors = -1, do_drops = -1, do_fifo = -1, do_compressed = -1,
488 - do_events = -1;
532 + do_events = -1, do_speed = -1, do_duplex = -1, do_operstate = -1;
533 static char *path_to_sys_devices_virtual_net = NULL, *path_to_sys_class_net_speed = NULL,
534 *proc_net_dev_filename = NULL;
535 static char *path_to_sys_class_net_duplex = NULL;
536 static char *path_to_sys_class_net_operstate = NULL;
493 - static long long int dt_to_refresh_speed = 0;
494 - static long long int dt_to_refresh_duplex = 0;
495 - static long long int dt_to_refresh_operstate = 0;
537
538 if(unlikely(enable_new_interfaces == -1)) {
539 char filename[FILENAME_MAX + 1];
@@ -522,19 +563,11 @@ int do_proc_net_dev(int update_every, usec_t dt) {
563 do_fifo = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "fifo for all interfaces", CONFIG_BOOLEAN_AUTO);
564 do_compressed = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "compressed packets for all interfaces", CONFIG_BOOLEAN_AUTO);
565 do_events = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "frames, collisions, carrier counters for all interfaces", CONFIG_BOOLEAN_AUTO);
566 + do_speed = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "speed for all interfaces", CONFIG_BOOLEAN_AUTO);
567 + do_duplex = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "duplex for all interfaces", CONFIG_BOOLEAN_AUTO);
568 + do_operstate = config_get_boolean_ondemand(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "operstate for all interfaces", CONFIG_BOOLEAN_AUTO);
569
570 disabled_list = simple_pattern_create(config_get(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "disable by default interfaces matching", "lo fireqos* *-ifb"), NULL, SIMPLE_PATTERN_EXACT);
527 -
528 - dt_to_refresh_speed = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface speed every seconds", 10) * USEC_PER_SEC;
529 - dt_to_refresh_duplex = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface duplex every seconds", 10) * USEC_PER_SEC;
530 - dt_to_refresh_operstate = config_get_number(CONFIG_SECTION_PLUGIN_PROC_NETDEV, "refresh interface operstate every seconds", 10) * USEC_PER_SEC;
531 -
532 - if (dt_to_refresh_operstate < 0)
533 - dt_to_refresh_operstate = 0;
534 - if (dt_to_refresh_duplex < 0)
535 - dt_to_refresh_duplex = 0;
536 - if (dt_to_refresh_speed < 0)
537 - dt_to_refresh_speed = 0;
571 }
572
573 if(unlikely(!ff)) {
@@ -612,6 +645,9 @@ int do_proc_net_dev(int update_every, usec_t dt) {
645 d->do_fifo = config_get_boolean_ondemand(buffer, "fifo", do_fifo);
646 d->do_compressed = config_get_boolean_ondemand(buffer, "compressed", do_compressed);
647 d->do_events = config_get_boolean_ondemand(buffer, "events", do_events);
648 + d->do_speed = config_get_boolean_ondemand(buffer, "speed", do_speed);
649 + d->do_duplex = config_get_boolean_ondemand(buffer, "duplex", do_duplex);
650 + d->do_operstate = config_get_boolean_ondemand(buffer, "operstate", do_operstate);
651 }
652
653 if(unlikely(!d->enabled))
@@ -659,6 +695,39 @@ int do_proc_net_dev(int update_every, usec_t dt) {
695 d->tcarrier = str2kernel_uint_t(procfile_lineword(ff, l, 15));
696 }
697
698 + if (d->do_duplex != CONFIG_BOOLEAN_NO && d->filename_duplex) {
699 + char buffer[STATE_LENGTH_MAX + 1];
700 +
701 + if (read_file(d->filename_duplex, buffer, STATE_LENGTH_MAX)) {
702 + error("Cannot refresh interface %s duplex state by reading '%s'. I will stop updating it.", d->name, d->filename_duplex);
703 + freez(d->filename_duplex);
704 + d->filename_duplex = NULL;
705 + } else {
706 + // values can be unknown, half or full -- just check the first letter for speed
707 + if (buffer[0] == 'f')
708 + d->duplex = 2;
709 + else if (buffer[0] == 'h')
710 + d->duplex = 1;
711 + else
712 + d->duplex = 0;
713 + }
714 + }
715 +
716 + if(d->do_operstate != CONFIG_BOOLEAN_NO && d->filename_operstate) {
717 + char buffer[STATE_LENGTH_MAX + 1], *trimmed_buffer;
718 +
719 + if (read_file(d->filename_operstate, buffer, STATE_LENGTH_MAX)) {
720 + error(
721 + "Cannot refresh %s operstate by reading '%s'. Will not update its status anymore.",
722 + d->name, d->filename_operstate);
723 + freez(d->filename_operstate);
724 + d->filename_operstate = NULL;
725 + } else {
726 + trimmed_buffer = trim(buffer);
727 + d->operstate = get_operstate(trimmed_buffer);
728 + }
729 + }
730 +
731 //info("PROC_NET_DEV: %s speed %zu, bytes %zu/%zu, packets %zu/%zu/%zu, errors %zu/%zu, drops %zu/%zu, fifo %zu/%zu, compressed %zu/%zu, rframe %zu, tcollisions %zu, tcarrier %zu"
732 // , d->name, d->speed
733 // , d->rbytes, d->tbytes
@@ -715,102 +784,117 @@ int do_proc_net_dev(int update_every, usec_t dt) {
784
785 // update the interface speed
786 if(d->filename_speed) {
718 - d->speed_last_collected_usec += dt;
719 -
720 - if(unlikely(d->speed_last_collected_usec >= (usec_t)dt_to_refresh_speed)) {
721 -
722 - if(unlikely(!d->chart_var_speed)) {
723 - d->chart_var_speed = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "nic_speed_max");
724 - if(!d->chart_var_speed) {
725 - error("Cannot create interface %s chart variable 'nic_speed_max'. Will not update its speed anymore.", d->name);
726 - freez(d->filename_speed);
727 - d->filename_speed = NULL;
728 - }
787 + if(unlikely(!d->chart_var_speed)) {
788 + d->chart_var_speed = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "nic_speed_max");
789 + if(!d->chart_var_speed) {
790 + error("Cannot create interface %s chart variable 'nic_speed_max'. Will not update its speed anymore.", d->name);
791 + freez(d->filename_speed);
792 + d->filename_speed = NULL;
793 }
794 + }
795
731 - if(d->filename_speed && d->chart_var_speed) {
732 - if(read_single_number_file(d->filename_speed, (unsigned long long *) &d->speed)) {
733 - error("Cannot refresh interface %s speed by reading '%s'. Will not update its speed anymore.", d->name, d->filename_speed);
734 - freez(d->filename_speed);
735 - d->filename_speed = NULL;
736 - }
737 - else {
738 - rrdsetvar_custom_chart_variable_set(d->chart_var_speed, (calculated_number) d->speed);
739 - d->speed_last_collected_usec = 0;
796 + if(d->filename_speed && d->chart_var_speed) {
797 + if(read_single_number_file(d->filename_speed, (unsigned long long *) &d->speed)) {
798 + error("Cannot refresh interface %s speed by reading '%s'. Will not update its speed anymore.", d->name, d->filename_speed);
799 + freez(d->filename_speed);
800 + d->filename_speed = NULL;
801 + }
802 + else {
803 + rrdsetvar_custom_chart_variable_set(d->chart_var_speed, (calculated_number) d->speed * KILOBITS_IN_A_MEGABIT);
804 +
805 + if(d->do_speed != CONFIG_BOOLEAN_NO) {
806 + if(unlikely(!d->st_speed)) {
807 + d->st_speed = rrdset_create_localhost(
808 + d->chart_type_net_speed
809 + , d->chart_id_net_speed
810 + , NULL
811 + , d->chart_family
812 + , "net.speed"
813 + , "Interface Speed"
814 + , "kilobits/s"
815 + , PLUGIN_PROC_NAME
816 + , PLUGIN_PROC_MODULE_NETDEV_NAME
817 + , d->priority + 7
818 + , update_every
819 + , RRDSET_TYPE_LINE
820 + );
821 +
822 + rrdset_flag_set(d->st_speed, RRDSET_FLAG_DETAIL);
823 +
824 + rrdset_update_labels(d->st_speed, d->chart_labels);
825 +
826 + d->rd_speed = rrddim_add(d->st_speed, "speed", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
827 + }
828 + else rrdset_next(d->st_speed);
829 +
830 + rrddim_set_by_pointer(d->st_speed, d->rd_speed, (collected_number)d->speed * KILOBITS_IN_A_MEGABIT);
831 + rrdset_done(d->st_speed);
832 }
833 }
834 }
835 }
836 + }
837
745 - if (d->filename_duplex) {
746 - d->duplex_last_collected_usec += dt;
838 + // --------------------------------------------------------------------
839
748 - if (unlikely(d->duplex_last_collected_usec >= (usec_t)dt_to_refresh_duplex)) {
749 - if (unlikely(!d->chart_var_duplex)) {
750 - d->chart_var_duplex = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "duplex");
751 - if (!d->chart_var_duplex) {
752 - error("Cannot create interface %s chart variable 'duplex'. Will not update the duplex status anymore.", d->name);
753 - freez(d->filename_duplex);
754 - d->filename_duplex = NULL;
755 - }
756 - }
840 + if(d->do_duplex != CONFIG_BOOLEAN_NO && d->filename_duplex) {
841 + if(unlikely(!d->st_duplex)) {
842 + d->st_duplex = rrdset_create_localhost(
843 + d->chart_type_net_duplex
844 + , d->chart_id_net_duplex
845 + , NULL
846 + , d->chart_family
847 + , "net.duplex"
848 + , "Interface Duplex State"
849 + , "state"
850 + , PLUGIN_PROC_NAME
851 + , PLUGIN_PROC_MODULE_NETDEV_NAME
852 + , d->priority + 8
853 + , update_every
854 + , RRDSET_TYPE_LINE
855 + );
856
758 - if (d->filename_duplex && d->chart_var_duplex) {
759 - char buffer[32 + 1];
760 -
761 - if (read_file(d->filename_duplex, buffer, 32)) {
762 - error("Cannot refresh interface %s duplex state by reading '%s'. I will stop updating it.", d->name, d->filename_duplex);
763 - freez(d->filename_duplex);
764 - d->filename_duplex = NULL;
765 - } else {
766 - // values can be unknown, half or full -- just check the first letter for speed
767 - if (buffer[0] == 'f')
768 - d->duplex = 2;
769 - else if (buffer[0] == 'h')
770 - d->duplex = 1;
771 - else
772 - d->duplex = 0;
773 -
774 - rrdsetvar_custom_chart_variable_set(d->chart_var_duplex, (calculated_number)d->duplex);
775 - d->duplex_last_collected_usec = 0;
776 - }
777 - }
778 - }
857 + rrdset_flag_set(d->st_duplex, RRDSET_FLAG_DETAIL);
858 +
859 + rrdset_update_labels(d->st_duplex, d->chart_labels);
860 +
861 + d->rd_duplex = rrddim_add(d->st_duplex, "duplex", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
862 }
863 + else rrdset_next(d->st_duplex);
864
781 - if (d->filename_operstate) {
782 - d->operstate_last_collected_usec += dt;
783 -
784 - if (unlikely(d->operstate_last_collected_usec >= (usec_t)dt_to_refresh_operstate)) {
785 - if (unlikely(!d->chart_var_operstate)) {
786 - d->chart_var_operstate = rrdsetvar_custom_chart_variable_create(d->st_bandwidth, "operstate");
787 - if (!d->chart_var_operstate) {
788 - error(
789 - "Cannot create interface %s chart variable 'operstate'. I will stop updating it.",
790 - d->name);
791 - freez(d->filename_operstate);
792 - d->filename_operstate = NULL;
793 - }
794 - }
865 + rrddim_set_by_pointer(d->st_duplex, d->rd_duplex, (collected_number)d->duplex);
866 + rrdset_done(d->st_duplex);
867 + }
868
796 - if (d->filename_operstate && d->chart_var_operstate) {
797 - char buffer[32 + 1], *trimmed_buffer;
798 -
799 - if (read_file(d->filename_operstate, buffer, 32)) {
800 - error(
801 - "Cannot refresh %s operstate by reading '%s'. Will not update its status anymore.",
802 - d->name, d->filename_operstate);
803 - freez(d->filename_operstate);
804 - d->filename_operstate = NULL;
805 - } else {
806 - trimmed_buffer = trim(buffer);
807 - d->operstate = get_operstate(trimmed_buffer);
808 - rrdsetvar_custom_chart_variable_set(d->chart_var_operstate, (calculated_number)d->operstate);
809 - d->operstate_last_collected_usec = 0;
810 - }
811 - }
812 - }
869 + // --------------------------------------------------------------------
870 +
871 + if(d->do_operstate != CONFIG_BOOLEAN_NO && d->filename_operstate) {
872 + if(unlikely(!d->st_operstate)) {
873 + d->st_operstate = rrdset_create_localhost(
874 + d->chart_type_net_operstate
875 + , d->chart_id_net_operstate
876 + , NULL
877 + , d->chart_family
878 + , "net.operstate"
879 + , "Interface Operational State"
880 + , "state"
881 + , PLUGIN_PROC_NAME
882 + , PLUGIN_PROC_MODULE_NETDEV_NAME
883 + , d->priority + 9
884 + , update_every
885 + , RRDSET_TYPE_LINE
886 + );
887 +
888 + rrdset_flag_set(d->st_operstate, RRDSET_FLAG_DETAIL);
889 +
890 + rrdset_update_labels(d->st_operstate, d->chart_labels);
891 +
892 + d->rd_operstate = rrddim_add(d->st_operstate, "state", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
893 }
894 + else rrdset_next(d->st_operstate);
895 +
896 + rrddim_set_by_pointer(d->st_operstate, d->rd_operstate, (collected_number)d->operstate);
897 + rrdset_done(d->st_operstate);
898 }
899
900 // --------------------------------------------------------------------
health/health.d/net.conf
+2 -2
@@ -20,7 +20,7 @@
20 hosts: *
21 families: *
22 lookup: average -1m unaligned absolute of received
23 - calc: ($interface_speed > 0) ? ($this * 100 / ($interface_speed * 1000)) : ( nan )
23 + calc: ($interface_speed > 0) ? ($this * 100 / ($interface_speed)) : ( nan )
24 units: %
25 every: 10s
26 warn: $this > (($status >= $WARNING) ? (85) : (90))
@@ -34,7 +34,7 @@
34 hosts: *
35 families: *
36 lookup: average -1m unaligned absolute of sent
37 - calc: ($interface_speed > 0) ? ($this * 100 / ($interface_speed * 1000)) : ( nan )
37 + calc: ($interface_speed > 0) ? ($this * 100 / ($interface_speed)) : ( nan )
38 units: %
39 every: 10s
40 warn: $this > (($status >= $WARNING) ? (85) : (90))
libnetdata/libnetdata.h
+2 -1
@@ -291,7 +291,8 @@ extern char *read_by_filename(char *filename, long *file_size);
291 #endif
292 #endif
293
294 -#define BITS_IN_A_KILOBIT 1000
294 +#define BITS_IN_A_KILOBIT 1000
295 +#define KILOBITS_IN_A_MEGABIT 1000
296
297 /* misc. */
298 #define UNUSED(x) (void)(x)