]> git.ipfire.org Git - people/ms/network.git/blame - src/networkd/daemon.c
networkd: Collect stats regulary and emit them on dbus
[people/ms/network.git] / src / networkd / daemon.c
CommitLineData
112358f3
MT
1/*#############################################################################
2# #
3# IPFire.org - A linux based firewall #
4# Copyright (C) 2023 IPFire Network Development Team #
5# #
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. #
10# #
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. #
15# #
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/>. #
18# #
19#############################################################################*/
20
025f60f1 21#include <errno.h>
112358f3
MT
22#include <stdlib.h>
23
09a6af17 24#include <systemd/sd-bus.h>
8a88982f 25#include <systemd/sd-daemon.h>
b286cd83 26#include <systemd/sd-device.h>
c7e1b5db 27#include <systemd/sd-event.h>
e62b300e 28#include <systemd/sd-netlink.h>
c7e1b5db 29
09a6af17 30#include "bus.h"
2ac78f28 31#include "config.h"
112358f3 32#include "daemon.h"
b286cd83 33#include "devmon.h"
eaf649ee 34#include "link.h"
18b8c841 35#include "links.h"
c251a9dd 36#include "logging.h"
b8db2713 37#include "ports.h"
15240e08 38#include "stats-collector.h"
19e74c9b 39#include "zone.h"
0c8e7342 40#include "zones.h"
112358f3 41
b286cd83
MT
42// Increase the receive buffer to 128 MiB
43#define RCVBUF_SIZE 128 * 1024 * 1024
44
112358f3
MT
45struct nw_daemon {
46 int nrefs;
c7e1b5db 47
2361667e 48 nw_config* config;
2ac78f28 49
c7e1b5db
MT
50 // Event Loop
51 sd_event* loop;
09a6af17 52
e62b300e
MT
53 // Netlink Connection
54 sd_netlink* rtnl;
55
09a6af17
MT
56 // DBus Connection
57 sd_bus* bus;
19e74c9b 58
b286cd83
MT
59 // udev Connection
60 sd_device_monitor* devmon;
61
18b8c841 62 // Links
2361667e 63 nw_links* links;
18b8c841 64
19e74c9b 65 // Zones
2361667e 66 nw_zones* zones;
b8db2713
MT
67
68 // Ports
2361667e 69 nw_ports* ports;
b8db2713 70
15240e08
MT
71 // Stats Collector
72 sd_event_source* stats_collector_event;
112358f3
MT
73};
74
27a3a596 75static int __nw_daemon_terminate(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1
MT
76 void* data) {
77 DEBUG("Received signal to terminate...\n");
78
79 return sd_event_exit(sd_event_source_get_event(source), 0);
80}
81
27a3a596 82static int __nw_daemon_reload(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1 83 void* data) {
2361667e 84 nw_daemon* daemon = (nw_daemon*)daemon;
27a3a596 85
025f60f1
MT
86 DEBUG("Received signal to reload...\n");
87
27a3a596
MT
88 // Reload the daemon
89 nw_daemon_reload(daemon);
025f60f1
MT
90
91 return 0;
92}
93
2361667e 94static int nw_daemon_setup_loop(nw_daemon* daemon) {
c7e1b5db
MT
95 int r;
96
97 // Fetch a reference to the default event loop
98 r = sd_event_default(&daemon->loop);
99 if (r < 0) {
025f60f1 100 ERROR("Could not setup event loop: %s\n", strerror(-r));
c7e1b5db
MT
101 return 1;
102 }
103
3b2316e4
MT
104 // Enable the watchdog
105 r = sd_event_set_watchdog(daemon->loop, 1);
106 if (r < 0) {
025f60f1
MT
107 ERROR("Could not activate watchdog: %s\n", strerror(-r));
108 return 1;
109 }
110
111 // Listen for SIGTERM
112 r = sd_event_add_signal(daemon->loop, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 113 __nw_daemon_terminate, daemon);
025f60f1
MT
114 if (r < 0) {
115 ERROR("Could not register handling SIGTERM: %s\n", strerror(-r));
116 return 1;
117 }
118
119 // Listen for SIGINT
120 r = sd_event_add_signal(daemon->loop, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 121 __nw_daemon_terminate, daemon);
025f60f1
MT
122 if (r < 0) {
123 ERROR("Could not register handling SIGINT: %s\n", strerror(-r));
124 return 1;
125 }
126
127 // Listen for SIGHUP
128 r = sd_event_add_signal(daemon->loop, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 129 __nw_daemon_reload, daemon);
025f60f1
MT
130 if (r < 0) {
131 ERROR("Could not register handling SIGHUP: %s\n", strerror(-r));
3b2316e4
MT
132 return 1;
133 }
134
c7e1b5db
MT
135 return 0;
136}
137
2361667e 138static int nw_daemon_load_config(nw_daemon* daemon) {
c7e1b5db
MT
139 int r;
140
2ac78f28 141 // Read configuration file
b076fa8b 142 r = nw_config_create(&daemon->config, CONFIG_DIR "/settings");
2ac78f28
MT
143 if (r)
144 return r;
145
19e74c9b
MT
146 return r;
147}
148
2361667e 149static int nw_start_device_monitor(nw_daemon* daemon) {
b286cd83
MT
150 int r;
151
152 const char* subsystems[] = {
153 "net",
154 "ieee80211",
155 "rfkill",
156 NULL,
157 };
158
159 // Create a new connection to monitor any devices
160 r = sd_device_monitor_new(&daemon->devmon);
161 if (r < 0) {
162 ERROR("Could not inititalize the device monitor: %m\n");
163 return 1;
164 }
165
166 // Increase the receive buffer
167 r = sd_device_monitor_set_receive_buffer_size(daemon->devmon, RCVBUF_SIZE);
168 if (r < 0) {
169 ERROR("Could not increase buffer size for the device monitor: %m\n");
170 return 1;
171 }
172
173 // Filter for events for all relevant subsystems
174 for (const char** subsystem = subsystems; *subsystem; subsystem++) {
175 r = sd_device_monitor_filter_add_match_subsystem_devtype(
176 daemon->devmon, *subsystem, NULL);
177 if (r < 1) {
178 ERROR("Could not add device monitor for the %s subsystem: %m\n", *subsystem);
179 return 1;
180 }
181 }
182
183 // Attach the device monitor to the event loop
184 r = sd_device_monitor_attach_event(daemon->devmon, daemon->loop);
185 if (r < 0) {
186 ERROR("Could not attach the device monitor to the event loop: %m\n");
187 return 1;
188 }
189
190 // Start processing events...
191 r = sd_device_monitor_start(daemon->devmon, nw_devmon_handle_uevent, daemon);
192 if (r < 0) {
193 ERROR("Could not start the device monitor: %m\n");
194 return 1;
195 }
196
197 return 0;
198}
199
2361667e 200static int nw_daemon_connect_rtnl(nw_daemon* daemon, int fd) {
e62b300e
MT
201 int r;
202
203 // Connect to Netlink
204 r = sd_netlink_open(&daemon->rtnl);
205 if (r < 0) {
206 ERROR("Could not connect to the kernel's netlink interface: %m\n");
207 return 1;
208 }
209
210 // Increase the receive buffer
211 r = sd_netlink_increase_rxbuf(daemon->rtnl, RCVBUF_SIZE);
212 if (r < 0) {
213 ERROR("Could not increase receive buffer for the netlink socket: %m\n");
214 return 1;
215 }
216
217 // Connect it to the event loop
218 r = sd_netlink_attach_event(daemon->rtnl, daemon->loop, 0);
219 if (r < 0) {
220 ERROR("Could not connect the netlink socket to the event loop: %m\n");
221 return 1;
222 }
223
224 // Register callback for new interfaces
eaf649ee 225 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_NEWLINK, nw_link_process, NULL,
e62b300e
MT
226 daemon, "networkd-RTM_NEWLINK");
227 if (r < 0) {
228 ERROR("Could not register RTM_NEWLINK: %m\n");
229 return 1;
230 }
231
766f08ca
MT
232 // Register callback for deleted interfaces
233 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_DELLINK, nw_link_process, NULL,
234 daemon, "networkd-RTM_DELLINK");
235 if (r < 0) {
236 ERROR("Could not register RTM_DELLINK: %m\n");
237 return 1;
238 }
239
e62b300e
MT
240 return 0;
241}
242
2361667e 243static int nw_daemon_enumerate_links(nw_daemon* daemon) {
18b8c841
MT
244 int r;
245
246 // Create a new links container
247 r = nw_links_create(&daemon->links, daemon);
248 if (r)
249 return r;
250
251 return nw_links_enumerate(daemon->links);
252}
253
2361667e 254static int nw_daemon_enumerate_ports(nw_daemon* daemon) {
b8db2713
MT
255 int r;
256
257 // Create a new ports container
258 r = nw_ports_create(&daemon->ports, daemon);
259 if (r)
260 return r;
261
262 return nw_ports_enumerate(daemon->ports);
263}
264
7af642e1
MT
265static int nw_daemon_enumerate_zones(nw_daemon* daemon) {
266 int r;
267
268 // Create a new zones container
269 r = nw_zones_create(&daemon->zones, daemon);
270 if (r)
271 return r;
272
273 return nw_zones_enumerate(daemon->zones);
274}
275
2361667e 276static int nw_daemon_enumerate(nw_daemon* daemon) {
18b8c841
MT
277 int r;
278
279 // Links
280 r = nw_daemon_enumerate_links(daemon);
281 if (r)
282 return r;
283
b8db2713
MT
284 // Ports
285 r = nw_daemon_enumerate_ports(daemon);
286 if (r)
287 return r;
288
7af642e1
MT
289 // Zones
290 r = nw_daemon_enumerate_zones(daemon);
291 if (r)
292 return r;
293
18b8c841
MT
294 return 0;
295}
296
b9769b09
MT
297static int __nw_daemon_reconfigure(sd_event_source* s, void* data) {
298 nw_daemon* daemon = (nw_daemon*)data;
299 int r;
300
301 DEBUG("Reconfiguring...\n");
302
303 // Reconfigure all zones
304 r = nw_zones_reconfigure(daemon->zones);
305 if (r)
306 return r;
307
308 // Reconfigure all ports
309 r = nw_ports_reconfigure(daemon->ports);
310 if (r)
311 return r;
312
313 return 0;
314}
315
316static int nw_daemon_reconfigure(nw_daemon* daemon) {
317 int r;
318
319 r = sd_event_add_defer(daemon->loop, NULL, __nw_daemon_reconfigure, daemon);
320 if (r) {
321 ERROR("Could not schedule re-configuration task: %m\n");
322 return r;
323 }
324
325 return 0;
326}
327
15240e08
MT
328static int nw_daemon_starts_stats_collector(nw_daemon* daemon) {
329 sd_event_source* s = NULL;
330 int r;
331
332 // Register the stats collector main function
333 r = sd_event_add_time_relative(daemon->loop, &s, CLOCK_MONOTONIC, 0, 0,
334 nw_stats_collector, daemon);
335 if (r < 0) {
336 ERROR("Could not start the stats collector: %m\n");
337 goto ERROR;
338 }
339
340 // Keep calling the stats collector for forever
341 r = sd_event_source_set_enabled(s, SD_EVENT_ON);
342 if (r < 0)
343 goto ERROR;
344
345 // Keep a reference to the event source
346 daemon->stats_collector_event = sd_event_source_ref(s);
347
348ERROR:
349 if (s)
350 sd_event_source_unref(s);
351
352 return r;
353}
354
2361667e 355static int nw_daemon_setup(nw_daemon* daemon) {
19e74c9b
MT
356 int r;
357
358 // Read the configuration
359 r = nw_daemon_load_config(daemon);
360 if (r)
361 return r;
362
c7e1b5db
MT
363 // Setup the event loop
364 r = nw_daemon_setup_loop(daemon);
365 if (r)
366 return r;
367
e62b300e
MT
368 // Connect to the kernel's netlink interface
369 r = nw_daemon_connect_rtnl(daemon, 0);
370 if (r)
371 return r;
372
09a6af17 373 // Connect to the system bus
442b2fc2 374 r = nw_bus_connect(&daemon->bus, daemon->loop, daemon);
09a6af17
MT
375 if (r)
376 return r;
377
b286cd83
MT
378 // Connect to udev
379 r = nw_start_device_monitor(daemon);
380 if (r)
381 return r;
382
18b8c841
MT
383 // Enumerate everything we need to know
384 r = nw_daemon_enumerate(daemon);
385 if (r)
386 return r;
387
b9769b09
MT
388 // (Re-)configure everything
389 r = nw_daemon_reconfigure(daemon);
390 if (r)
391 return r;
392
15240e08
MT
393 // Start the stats collector
394 r = nw_daemon_starts_stats_collector(daemon);
395 if (r)
396 return r;
397
c7e1b5db
MT
398 return 0;
399}
400
2361667e 401int nw_daemon_create(nw_daemon** daemon) {
c7e1b5db
MT
402 int r;
403
2361667e 404 nw_daemon* d = calloc(1, sizeof(*d));
112358f3
MT
405 if (!d)
406 return 1;
407
408 // Initialize reference counter
409 d->nrefs = 1;
410
c7e1b5db
MT
411 // Setup the daemon
412 r = nw_daemon_setup(d);
413 if (r)
414 goto ERROR;
415
416 // Set the reference
417 *daemon = d;
418
112358f3 419 return 0;
c7e1b5db
MT
420
421ERROR:
422 nw_daemon_unref(d);
423
424 return r;
112358f3
MT
425}
426
2361667e 427static void nw_daemon_cleanup(nw_daemon* daemon) {
b8db2713
MT
428 if (daemon->ports)
429 nw_ports_unref(daemon->ports);
0c8e7342
MT
430 if (daemon->zones)
431 nw_zones_unref(daemon->zones);
18b8c841
MT
432 if (daemon->links)
433 nw_links_unref(daemon->links);
2ac78f28
MT
434 if (daemon->config)
435 nw_config_unref(daemon->config);
18b8c841
MT
436}
437
2361667e 438static void nw_daemon_free(nw_daemon* daemon) {
18b8c841
MT
439 // Cleanup common objects
440 nw_daemon_cleanup(daemon);
441
15240e08
MT
442 if (daemon->stats_collector_event)
443 sd_event_source_unref(daemon->stats_collector_event);
09a6af17
MT
444 if (daemon->bus)
445 sd_bus_unref(daemon->bus);
c7e1b5db
MT
446 if (daemon->loop)
447 sd_event_unref(daemon->loop);
448
112358f3
MT
449 free(daemon);
450}
451
2361667e 452nw_daemon* nw_daemon_ref(nw_daemon* daemon) {
112358f3
MT
453 daemon->nrefs++;
454
455 return daemon;
456}
457
2361667e 458nw_daemon* nw_daemon_unref(nw_daemon* daemon) {
112358f3
MT
459 if (--daemon->nrefs > 0)
460 return daemon;
461
462 nw_daemon_free(daemon);
463 return NULL;
464}
c7e1b5db
MT
465
466/*
467 This function contains the main loop of the daemon...
468*/
2361667e 469int nw_daemon_run(nw_daemon* daemon) {
c7e1b5db
MT
470 int r;
471
8a88982f
MT
472 // We are now ready to process any requests
473 sd_notify(0, "READY=1\n" "STATUS=Processing requests...");
474
c7e1b5db
MT
475 // Launch the event loop
476 r = sd_event_loop(daemon->loop);
8a88982f
MT
477 if (r < 0) {
478 ERROR("Could not run the event loop: %s\n", strerror(-r));
479 goto ERROR;
c7e1b5db
MT
480 }
481
8a88982f
MT
482 // Let systemd know that we are shutting down
483 sd_notify(0, "STOPPING=1\n" "STATUS=Shutting down...");
484
605e975f
MT
485 // Save the configuration
486 r = nw_daemon_save(daemon);
487 if (r)
488 goto ERROR;
489
18b8c841
MT
490 // Cleanup everything
491 nw_daemon_cleanup(daemon);
492
c7e1b5db 493 return 0;
8a88982f
MT
494
495ERROR:
496 sd_notifyf(0, "ERRNO=%i", -r);
497
18b8c841
MT
498 // Cleanup everything
499 nw_daemon_cleanup(daemon);
500
8a88982f 501 return 1;
c7e1b5db 502}
27a3a596 503
2361667e 504int nw_daemon_reload(nw_daemon* daemon) {
27a3a596
MT
505 DEBUG("Reloading daemon...\n");
506
507 // XXX TODO
508
509 return 0;
510}
0c8e7342 511
605e975f
MT
512/*
513 Saves the configuration to disk
514*/
515int nw_daemon_save(nw_daemon* daemon) {
516 int r;
517
518 DEBUG("Saving configuration...\n");
519
520 // Save settings
521 r = nw_config_write(daemon->config);
522 if (r)
523 return r;
524
525 // Save ports
526 r = nw_ports_save(daemon->ports);
527 if (r)
528 return r;
529
530 // Save zones
531 r = nw_zones_save(daemon->zones);
532 if (r)
533 return r;
534
535 return 0;
536}
537
15240e08
MT
538/*
539 Bus
540*/
541sd_bus* nw_daemon_get_bus(nw_daemon* daemon) {
542 return daemon->bus;
543}
544
eaf649ee
MT
545/*
546 Netlink
547*/
2361667e 548sd_netlink* nw_daemon_get_rtnl(nw_daemon* daemon) {
eaf649ee
MT
549 return daemon->rtnl;
550}
551
766f08ca
MT
552/*
553 Links
554*/
2361667e 555nw_links* nw_daemon_links(nw_daemon* daemon) {
766f08ca
MT
556 return nw_links_ref(daemon->links);
557}
558
2361667e 559void nw_daemon_drop_link(nw_daemon* daemon, nw_link* link) {
766f08ca
MT
560 if (!daemon->links)
561 return;
562
563 nw_links_drop_link(daemon->links, link);
564}
565
2361667e 566nw_link* nw_daemon_get_link_by_ifindex(nw_daemon* daemon, int ifindex) {
766f08ca
MT
567 if (!daemon->links)
568 return NULL;
569
570 return nw_links_get_by_ifindex(daemon->links, ifindex);
571}
572
2361667e 573nw_link* nw_daemon_get_link_by_name(nw_daemon* daemon, const char* name) {
30d4ab67
MT
574 if (!daemon->links)
575 return NULL;
576
577 return nw_links_get_by_name(daemon->links, name);
578}
579
7297ba7f
MT
580/*
581 Ports
582*/
2361667e 583nw_ports* nw_daemon_ports(nw_daemon* daemon) {
7297ba7f
MT
584 return nw_ports_ref(daemon->ports);
585}
586
611d4aca
MT
587int nw_daemon_ports_walk(nw_daemon* daemon, nw_ports_walk_callback callback, void* data) {
588 if (!daemon->ports)
589 return 0;
590
591 return nw_ports_walk(daemon->ports, callback, data);
592}
593
2361667e 594nw_port* nw_daemon_get_port_by_name(nw_daemon* daemon, const char* name) {
7297ba7f
MT
595 if (!daemon->ports)
596 return NULL;
597
598 return nw_ports_get_by_name(daemon->ports, name);
599}
600
bd9ffd6a
MT
601/*
602 Zones
603*/
604
2361667e 605nw_zones* nw_daemon_zones(nw_daemon* daemon) {
0c8e7342
MT
606 return nw_zones_ref(daemon->zones);
607}
bd9ffd6a 608
b4faae0a
MT
609int nw_daemon_zones_walk(nw_daemon* daemon, nw_zones_walk_callback callback, void* data) {
610 if (!daemon->zones)
611 return 0;
612
613 return nw_zones_walk(daemon->zones, callback, data);
614}
615
2361667e 616nw_zone* nw_daemon_get_zone_by_name(nw_daemon* daemon, const char* name) {
bd9ffd6a
MT
617 if (!daemon->zones)
618 return NULL;
619
620 return nw_zones_get_by_name(daemon->zones, name);
621}