1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <errno.h>
4 
5 #include "sd-event.h"
6 #include "sd-netlink.h"
7 
8 #include "networkd-link-bus.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-speed-meter.h"
12 
process_message(Manager * manager,sd_netlink_message * message)13 static int process_message(Manager *manager, sd_netlink_message *message) {
14         uint16_t type;
15         int ifindex, r;
16         Link *link;
17 
18         r = sd_netlink_message_get_type(message, &type);
19         if (r < 0)
20                 return r;
21 
22         if (type != RTM_NEWLINK)
23                 return 0;
24 
25         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
26         if (r < 0)
27                 return r;
28 
29         r = link_get_by_index(manager, ifindex, &link);
30         if (r < 0)
31                 return r;
32 
33         link->stats_old = link->stats_new;
34 
35         r = sd_netlink_message_read(message, IFLA_STATS64, sizeof link->stats_new, &link->stats_new);
36         if (r < 0)
37                 return r;
38 
39         link->stats_updated = true;
40 
41         return 0;
42 }
43 
speed_meter_handler(sd_event_source * s,uint64_t usec,void * userdata)44 static int speed_meter_handler(sd_event_source *s, uint64_t usec, void *userdata) {
45         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL, *reply = NULL;
46         Manager *manager = userdata;
47         usec_t usec_now;
48         Link *link;
49         int r;
50 
51         assert(s);
52         assert(userdata);
53 
54         r = sd_event_now(sd_event_source_get_event(s), CLOCK_MONOTONIC, &usec_now);
55         if (r < 0)
56                 return r;
57 
58         r = sd_event_source_set_time(s, usec_now + manager->speed_meter_interval_usec);
59         if (r < 0)
60                 return r;
61 
62         manager->speed_meter_usec_old = manager->speed_meter_usec_new;
63         manager->speed_meter_usec_new = usec_now;
64 
65         HASHMAP_FOREACH(link, manager->links_by_index)
66                 link->stats_updated = false;
67 
68         r = sd_rtnl_message_new_link(manager->rtnl, &req, RTM_GETLINK, 0);
69         if (r < 0) {
70                 log_warning_errno(r, "Failed to allocate RTM_GETLINK netlink message, ignoring: %m");
71                 return 0;
72         }
73 
74         r = sd_netlink_message_request_dump(req, true);
75         if (r < 0) {
76                 log_warning_errno(r, "Failed to set dump flag, ignoring: %m");
77                 return 0;
78         }
79 
80         r = sd_netlink_call(manager->rtnl, req, 0, &reply);
81         if (r < 0) {
82                 log_warning_errno(r, "Failed to call RTM_GETLINK, ignoring: %m");
83                 return 0;
84         }
85 
86         for (sd_netlink_message *i = reply; i; i = sd_netlink_message_next(i))
87                 (void) process_message(manager, i);
88 
89         return 0;
90 }
91 
manager_start_speed_meter(Manager * manager)92 int manager_start_speed_meter(Manager *manager) {
93         _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
94         int r;
95 
96         assert(manager);
97         assert(manager->event);
98 
99         if (!manager->use_speed_meter)
100                 return 0;
101 
102         r = sd_event_add_time(manager->event, &s, CLOCK_MONOTONIC, 0, 0, speed_meter_handler, manager);
103         if (r < 0)
104                 return r;
105 
106         r = sd_event_source_set_enabled(s, SD_EVENT_ON);
107         if (r < 0)
108                 return r;
109 
110         manager->speed_meter_event_source = TAKE_PTR(s);
111         return 0;
112 }
113