]> git.ipfire.org Git - people/ms/network.git/blame - src/networkd/daemon.c
networkd: Add scaffolding for ports
[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"
19e74c9b 37#include "zone.h"
0c8e7342 38#include "zones.h"
112358f3 39
b286cd83
MT
40// Increase the receive buffer to 128 MiB
41#define RCVBUF_SIZE 128 * 1024 * 1024
42
112358f3
MT
43struct nw_daemon {
44 int nrefs;
c7e1b5db 45
2ac78f28
MT
46 struct nw_config* config;
47
c7e1b5db
MT
48 // Event Loop
49 sd_event* loop;
09a6af17 50
e62b300e
MT
51 // Netlink Connection
52 sd_netlink* rtnl;
53
09a6af17
MT
54 // DBus Connection
55 sd_bus* bus;
19e74c9b 56
b286cd83
MT
57 // udev Connection
58 sd_device_monitor* devmon;
59
18b8c841
MT
60 // Links
61 struct nw_links* links;
62
19e74c9b 63 // Zones
0c8e7342 64 struct nw_zones* zones;
112358f3
MT
65};
66
27a3a596 67static int __nw_daemon_terminate(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1
MT
68 void* data) {
69 DEBUG("Received signal to terminate...\n");
70
71 return sd_event_exit(sd_event_source_get_event(source), 0);
72}
73
27a3a596 74static int __nw_daemon_reload(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1 75 void* data) {
27a3a596
MT
76 struct nw_daemon* daemon = (struct nw_daemon*)daemon;
77
025f60f1
MT
78 DEBUG("Received signal to reload...\n");
79
27a3a596
MT
80 // Reload the daemon
81 nw_daemon_reload(daemon);
025f60f1
MT
82
83 return 0;
84}
85
c7e1b5db
MT
86static int nw_daemon_setup_loop(struct nw_daemon* daemon) {
87 int r;
88
89 // Fetch a reference to the default event loop
90 r = sd_event_default(&daemon->loop);
91 if (r < 0) {
025f60f1 92 ERROR("Could not setup event loop: %s\n", strerror(-r));
c7e1b5db
MT
93 return 1;
94 }
95
3b2316e4
MT
96 // Enable the watchdog
97 r = sd_event_set_watchdog(daemon->loop, 1);
98 if (r < 0) {
025f60f1
MT
99 ERROR("Could not activate watchdog: %s\n", strerror(-r));
100 return 1;
101 }
102
103 // Listen for SIGTERM
104 r = sd_event_add_signal(daemon->loop, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 105 __nw_daemon_terminate, daemon);
025f60f1
MT
106 if (r < 0) {
107 ERROR("Could not register handling SIGTERM: %s\n", strerror(-r));
108 return 1;
109 }
110
111 // Listen for SIGINT
112 r = sd_event_add_signal(daemon->loop, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 113 __nw_daemon_terminate, daemon);
025f60f1
MT
114 if (r < 0) {
115 ERROR("Could not register handling SIGINT: %s\n", strerror(-r));
116 return 1;
117 }
118
119 // Listen for SIGHUP
120 r = sd_event_add_signal(daemon->loop, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK,
27a3a596 121 __nw_daemon_reload, daemon);
025f60f1
MT
122 if (r < 0) {
123 ERROR("Could not register handling SIGHUP: %s\n", strerror(-r));
3b2316e4
MT
124 return 1;
125 }
126
c7e1b5db
MT
127 return 0;
128}
129
19e74c9b 130static int nw_daemon_load_config(struct nw_daemon* daemon) {
c7e1b5db
MT
131 int r;
132
2ac78f28 133 // Read configuration file
b076fa8b 134 r = nw_config_create(&daemon->config, CONFIG_DIR "/settings");
2ac78f28
MT
135 if (r)
136 return r;
137
19e74c9b 138 // Load zones
0c8e7342 139 r = nw_zones_load(&daemon->zones);
19e74c9b
MT
140 if (r)
141 return r;
142
143 return r;
144}
145
b286cd83
MT
146static int nw_start_device_monitor(struct nw_daemon* daemon) {
147 int r;
148
149 const char* subsystems[] = {
150 "net",
151 "ieee80211",
152 "rfkill",
153 NULL,
154 };
155
156 // Create a new connection to monitor any devices
157 r = sd_device_monitor_new(&daemon->devmon);
158 if (r < 0) {
159 ERROR("Could not inititalize the device monitor: %m\n");
160 return 1;
161 }
162
163 // Increase the receive buffer
164 r = sd_device_monitor_set_receive_buffer_size(daemon->devmon, RCVBUF_SIZE);
165 if (r < 0) {
166 ERROR("Could not increase buffer size for the device monitor: %m\n");
167 return 1;
168 }
169
170 // Filter for events for all relevant subsystems
171 for (const char** subsystem = subsystems; *subsystem; subsystem++) {
172 r = sd_device_monitor_filter_add_match_subsystem_devtype(
173 daemon->devmon, *subsystem, NULL);
174 if (r < 1) {
175 ERROR("Could not add device monitor for the %s subsystem: %m\n", *subsystem);
176 return 1;
177 }
178 }
179
180 // Attach the device monitor to the event loop
181 r = sd_device_monitor_attach_event(daemon->devmon, daemon->loop);
182 if (r < 0) {
183 ERROR("Could not attach the device monitor to the event loop: %m\n");
184 return 1;
185 }
186
187 // Start processing events...
188 r = sd_device_monitor_start(daemon->devmon, nw_devmon_handle_uevent, daemon);
189 if (r < 0) {
190 ERROR("Could not start the device monitor: %m\n");
191 return 1;
192 }
193
194 return 0;
195}
196
e62b300e
MT
197static int nw_daemon_connect_rtnl(struct nw_daemon* daemon, int fd) {
198 int r;
199
200 // Connect to Netlink
201 r = sd_netlink_open(&daemon->rtnl);
202 if (r < 0) {
203 ERROR("Could not connect to the kernel's netlink interface: %m\n");
204 return 1;
205 }
206
207 // Increase the receive buffer
208 r = sd_netlink_increase_rxbuf(daemon->rtnl, RCVBUF_SIZE);
209 if (r < 0) {
210 ERROR("Could not increase receive buffer for the netlink socket: %m\n");
211 return 1;
212 }
213
214 // Connect it to the event loop
215 r = sd_netlink_attach_event(daemon->rtnl, daemon->loop, 0);
216 if (r < 0) {
217 ERROR("Could not connect the netlink socket to the event loop: %m\n");
218 return 1;
219 }
220
221 // Register callback for new interfaces
eaf649ee 222 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_NEWLINK, nw_link_process, NULL,
e62b300e
MT
223 daemon, "networkd-RTM_NEWLINK");
224 if (r < 0) {
225 ERROR("Could not register RTM_NEWLINK: %m\n");
226 return 1;
227 }
228
766f08ca
MT
229 // Register callback for deleted interfaces
230 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_DELLINK, nw_link_process, NULL,
231 daemon, "networkd-RTM_DELLINK");
232 if (r < 0) {
233 ERROR("Could not register RTM_DELLINK: %m\n");
234 return 1;
235 }
236
e62b300e
MT
237 return 0;
238}
239
18b8c841
MT
240static int nw_daemon_enumerate_links(struct nw_daemon* daemon) {
241 int r;
242
243 // Create a new links container
244 r = nw_links_create(&daemon->links, daemon);
245 if (r)
246 return r;
247
248 return nw_links_enumerate(daemon->links);
249}
250
251static int nw_daemon_enumerate(struct nw_daemon* daemon) {
252 int r;
253
254 // Links
255 r = nw_daemon_enumerate_links(daemon);
256 if (r)
257 return r;
258
259 return 0;
260}
261
19e74c9b
MT
262static int nw_daemon_setup(struct nw_daemon* daemon) {
263 int r;
264
265 // Read the configuration
266 r = nw_daemon_load_config(daemon);
267 if (r)
268 return r;
269
c7e1b5db
MT
270 // Setup the event loop
271 r = nw_daemon_setup_loop(daemon);
272 if (r)
273 return r;
274
e62b300e
MT
275 // Connect to the kernel's netlink interface
276 r = nw_daemon_connect_rtnl(daemon, 0);
277 if (r)
278 return r;
279
09a6af17 280 // Connect to the system bus
eaeca0f9 281 r = nw_bus_connect(daemon->bus, daemon->loop, daemon);
09a6af17
MT
282 if (r)
283 return r;
284
b286cd83
MT
285 // Connect to udev
286 r = nw_start_device_monitor(daemon);
287 if (r)
288 return r;
289
18b8c841
MT
290 // Enumerate everything we need to know
291 r = nw_daemon_enumerate(daemon);
292 if (r)
293 return r;
294
c7e1b5db
MT
295 return 0;
296}
297
112358f3 298int nw_daemon_create(struct nw_daemon** daemon) {
c7e1b5db
MT
299 int r;
300
112358f3
MT
301 struct nw_daemon* d = calloc(1, sizeof(*d));
302 if (!d)
303 return 1;
304
305 // Initialize reference counter
306 d->nrefs = 1;
307
c7e1b5db
MT
308 // Setup the daemon
309 r = nw_daemon_setup(d);
310 if (r)
311 goto ERROR;
312
313 // Set the reference
314 *daemon = d;
315
112358f3 316 return 0;
c7e1b5db
MT
317
318ERROR:
319 nw_daemon_unref(d);
320
321 return r;
112358f3
MT
322}
323
18b8c841 324static void nw_daemon_cleanup(struct nw_daemon* daemon) {
0c8e7342
MT
325 if (daemon->zones)
326 nw_zones_unref(daemon->zones);
18b8c841
MT
327 if (daemon->links)
328 nw_links_unref(daemon->links);
2ac78f28
MT
329 if (daemon->config)
330 nw_config_unref(daemon->config);
18b8c841
MT
331}
332
333static void nw_daemon_free(struct nw_daemon* daemon) {
334 // Cleanup common objects
335 nw_daemon_cleanup(daemon);
336
09a6af17
MT
337 if (daemon->bus)
338 sd_bus_unref(daemon->bus);
c7e1b5db
MT
339 if (daemon->loop)
340 sd_event_unref(daemon->loop);
341
112358f3
MT
342 free(daemon);
343}
344
345struct nw_daemon* nw_daemon_ref(struct nw_daemon* daemon) {
346 daemon->nrefs++;
347
348 return daemon;
349}
350
351struct nw_daemon* nw_daemon_unref(struct nw_daemon* daemon) {
352 if (--daemon->nrefs > 0)
353 return daemon;
354
355 nw_daemon_free(daemon);
356 return NULL;
357}
c7e1b5db
MT
358
359/*
360 This function contains the main loop of the daemon...
361*/
362int nw_daemon_run(struct nw_daemon* daemon) {
363 int r;
364
8a88982f
MT
365 // We are now ready to process any requests
366 sd_notify(0, "READY=1\n" "STATUS=Processing requests...");
367
c7e1b5db
MT
368 // Launch the event loop
369 r = sd_event_loop(daemon->loop);
8a88982f
MT
370 if (r < 0) {
371 ERROR("Could not run the event loop: %s\n", strerror(-r));
372 goto ERROR;
c7e1b5db
MT
373 }
374
8a88982f
MT
375 // Let systemd know that we are shutting down
376 sd_notify(0, "STOPPING=1\n" "STATUS=Shutting down...");
377
18b8c841
MT
378 // Cleanup everything
379 nw_daemon_cleanup(daemon);
380
c7e1b5db 381 return 0;
8a88982f
MT
382
383ERROR:
384 sd_notifyf(0, "ERRNO=%i", -r);
385
18b8c841
MT
386 // Cleanup everything
387 nw_daemon_cleanup(daemon);
388
8a88982f 389 return 1;
c7e1b5db 390}
27a3a596
MT
391
392int nw_daemon_reload(struct nw_daemon* daemon) {
393 DEBUG("Reloading daemon...\n");
394
395 // XXX TODO
396
397 return 0;
398}
0c8e7342 399
eaf649ee
MT
400/*
401 Netlink
402*/
403sd_netlink* nw_daemon_get_rtnl(struct nw_daemon* daemon) {
404 return daemon->rtnl;
405}
406
766f08ca
MT
407/*
408 Links
409*/
410struct nw_links* nw_daemon_links(struct nw_daemon* daemon) {
411 return nw_links_ref(daemon->links);
412}
413
414void nw_daemon_drop_link(struct nw_daemon* daemon, struct nw_link* link) {
415 if (!daemon->links)
416 return;
417
418 nw_links_drop_link(daemon->links, link);
419}
420
421struct nw_link* nw_daemon_get_link_by_ifindex(struct nw_daemon* daemon, int ifindex) {
422 if (!daemon->links)
423 return NULL;
424
425 return nw_links_get_by_ifindex(daemon->links, ifindex);
426}
427
bd9ffd6a
MT
428/*
429 Zones
430*/
431
0c8e7342
MT
432struct nw_zones* nw_daemon_zones(struct nw_daemon* daemon) {
433 return nw_zones_ref(daemon->zones);
434}
bd9ffd6a
MT
435
436struct nw_zone* nw_daemon_get_zone_by_name(struct nw_daemon* daemon, const char* name) {
437 if (!daemon->zones)
438 return NULL;
439
440 return nw_zones_get_by_name(daemon->zones, name);
441}