1 /*#############################################################################
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
19 #############################################################################*/
23 #include <systemd/sd-bus.h>
24 #include <systemd/sd-event.h>
28 #include "stats-collector.h"
31 static int __nw_stats_collector_port(nw_daemon
* daemon
, nw_port
* port
, void* data
) {
32 return nw_port_update_stats(port
);
35 static int __nw_stats_collector_zone(nw_daemon
* daemon
, nw_zone
* zone
, void* data
) {
36 return nw_zone_update_stats(zone
);
39 int nw_stats_collector(sd_event_source
* s
, long unsigned int usec
, void* data
) {
40 nw_daemon
* daemon
= (nw_daemon
*)data
;
43 DEBUG("Stats collector has been called\n");
45 // Schedule the next call
46 r
= sd_event_source_set_time(s
, usec
+ NW_STATS_COLLECTOR_INTERVAL
);
51 r
= nw_daemon_ports_walk(daemon
, __nw_stats_collector_port
, NULL
);
56 r
= nw_daemon_zones_walk(daemon
, __nw_stats_collector_zone
, NULL
);
63 static int nw_stats_collector_emit_stats(nw_daemon
* daemon
, const char* path
,
64 const char* interface
, const char* member
, const struct rtnl_link_stats64
* stats64
) {
65 sd_bus_message
* m
= NULL
;
68 sd_bus
* bus
= nw_daemon_get_bus(daemon
);
70 // Allocate a new message
71 r
= sd_bus_message_new_signal(bus
, &m
, path
, interface
, member
);
74 ERROR("Could not allocate bus message: %m\n");
79 r
= sd_bus_message_open_container(m
, 'a', "{st}");
81 ERROR("Could not open container: %m\n");
85 const struct stats64_entry
{
89 { "rx-packets", stats64
->rx_packets
},
90 { "tx-packets", stats64
->tx_packets
},
91 { "rx-bytes", stats64
->rx_bytes
},
92 { "tx-bytes", stats64
->tx_bytes
},
93 { "rx-errors", stats64
->rx_errors
},
94 { "tx-errors", stats64
->tx_errors
},
95 { "rx-dropped", stats64
->rx_dropped
},
96 { "tx-dropped", stats64
->tx_dropped
},
97 { "multicast", stats64
->multicast
},
98 { "collisions", stats64
->collisions
},
100 // Detailed RX errors
101 { "rx-length-errors", stats64
->rx_length_errors
},
102 { "rx-over-errors", stats64
->rx_over_errors
},
103 { "rx-crc-errors", stats64
->rx_crc_errors
},
104 { "rx-frame-errors", stats64
->rx_frame_errors
},
105 { "rx-fifo-errors", stats64
->rx_fifo_errors
},
106 { "rx-missed-errors", stats64
->rx_missed_errors
},
108 // Detailed TX errors
109 { "tx-aborted-errors", stats64
->tx_aborted_errors
},
110 { "tx-carrier-errors", stats64
->tx_carrier_errors
},
111 { "tx-fifo-errors", stats64
->tx_fifo_errors
},
112 { "tx-heartbeat-errors", stats64
->tx_heartbeat_errors
},
113 { "tx-window-errors", stats64
->tx_window_errors
},
118 for (const struct stats64_entry
* e
= entries
; e
->key
; e
++) {
119 r
= sd_bus_message_append(m
, "{st}", e
->key
, e
->value
);
121 ERROR("Could not set stat value: %m\n");
126 // Close the container
127 r
= sd_bus_message_close_container(m
);
129 ERROR("Could not close container: %m\n");
134 r
= sd_bus_send(bus
, m
, NULL
);
136 ERROR("Could not emit the stats signal for %s: %m\n", path
);
142 sd_bus_message_unref(m
);
147 int nw_stats_collector_emit_port_stats(nw_daemon
* daemon
, nw_port
* port
) {
148 const struct rtnl_link_stats64
* stats64
= NULL
;
152 // Fetch the bus path
153 path
= nw_port_bus_path(port
);
156 stats64
= nw_port_get_stats64(port
);
159 r
= nw_stats_collector_emit_stats(daemon
, path
,
160 "org.ipfire.network1.Port", "Stats", stats64
);
162 ERROR("Could not emit stats for port %s: %m\n", nw_port_name(port
));
173 int nw_stats_collector_emit_zone_stats(nw_daemon
* daemon
, nw_zone
* zone
) {
174 const struct rtnl_link_stats64
* stats64
= NULL
;
178 // Fetch the bus path
179 path
= nw_zone_bus_path(zone
);
182 stats64
= nw_zone_get_stats64(zone
);
185 r
= nw_stats_collector_emit_stats(daemon
, path
,
186 "org.ipfire.network1.Zone", "Stats", stats64
);
188 ERROR("Could not emit stats for zone %s: %m\n", nw_zone_name(zone
));