]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
networkd: handle SIGINT and SIGTERM
[thirdparty/systemd.git] / src / network / networkd-manager.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
3bef724f
TG
22#include <resolv.h>
23
f579559b
TG
24#include "path-util.h"
25#include "networkd.h"
26#include "libudev-private.h"
7b77ed8c 27#include "udev-util.h"
50add290 28#include "rtnl-util.h"
3bef724f 29#include "mkdir.h"
60ad0c85 30#include "virt.h"
f579559b 31
2ad8416d
ZJS
32const char* const network_dirs[] = {
33 "/etc/systemd/network",
34 "/run/systemd/network",
35 "/usr/lib/systemd/network",
36#ifdef HAVE_SPLIT_USER
37 "/lib/systemd/network",
38#endif
39 NULL};
40
0c2f9b84
TG
41static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
42 Manager *m = userdata;
43
44 assert(m);
45
46 log_received_signal(LOG_INFO, si);
47
48 sd_event_exit(m->event, 0);
49 return 0;
50}
51
52static int setup_signals(Manager *m) {
53 sigset_t mask;
54 int r;
55
56 assert(m);
57
58 assert_se(sigemptyset(&mask) == 0);
59 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
60 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
61
62 r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
63 if (r < 0)
64 return r;
65
66 r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
67 if (r < 0)
68 return r;
69
70 return 0;
71}
72
f579559b
TG
73int manager_new(Manager **ret) {
74 _cleanup_manager_free_ Manager *m = NULL;
75 int r;
76
77 m = new0(Manager, 1);
78 if (!m)
79 return -ENOMEM;
80
afc6adb5 81 r = sd_event_default(&m->event);
f579559b
TG
82 if (r < 0)
83 return r;
84
cde93897
LP
85 sd_event_set_watchdog(m->event, true);
86
151b9b96 87 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
f579559b
TG
88 if (r < 0)
89 return r;
90
1346b1f0 91 r = sd_bus_default_system(&m->bus);
bcbca829 92 if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
1346b1f0
TG
93 return r;
94
0c2f9b84
TG
95 r = setup_signals(m);
96 if (r < 0)
97 return r;
98
f579559b
TG
99 m->udev = udev_new();
100 if (!m->udev)
101 return -ENOMEM;
102
60ad0c85
TG
103 /* udev does not initialize devices inside containers,
104 * so we rely on them being already initialized before
105 * entering the container */
106 if (detect_container(NULL) > 0) {
107 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel");
108 if (!m->udev_monitor)
109 return -ENOMEM;
110 } else {
111 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
112 if (!m->udev_monitor)
113 return -ENOMEM;
114 }
f579559b
TG
115
116 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
117 if (!m->links)
118 return -ENOMEM;
119
52433f6b
TG
120 m->netdevs = hashmap_new(string_hash_func, string_compare_func);
121 if (!m->netdevs)
02b59d57
TG
122 return -ENOMEM;
123
f579559b
TG
124 LIST_HEAD_INIT(m->networks);
125
f579559b
TG
126 *ret = m;
127 m = NULL;
128
129 return 0;
130}
131
132void manager_free(Manager *m) {
0617ffab 133 Network *network;
1a436809 134 NetDev *netdev;
0617ffab
TG
135 Link *link;
136
624b5a63
TG
137 if (!m)
138 return;
139
f579559b
TG
140 udev_monitor_unref(m->udev_monitor);
141 udev_unref(m->udev);
1346b1f0 142 sd_bus_unref(m->bus);
f579559b 143 sd_event_source_unref(m->udev_event_source);
0c2f9b84
TG
144 sd_event_source_unref(m->sigterm_event_source);
145 sd_event_source_unref(m->sigint_event_source);
f579559b 146 sd_event_unref(m->event);
0617ffab
TG
147
148 while ((network = m->networks))
149 network_free(network);
150
151 while ((link = hashmap_first(m->links)))
152 link_free(link);
f579559b 153 hashmap_free(m->links);
0617ffab 154
52433f6b
TG
155 while ((netdev = hashmap_first(m->netdevs)))
156 netdev_free(netdev);
157 hashmap_free(m->netdevs);
02b59d57 158
f579559b
TG
159 sd_rtnl_unref(m->rtnl);
160
161 free(m);
162}
163
02b59d57
TG
164int manager_load_config(Manager *m) {
165 int r;
166
167 /* update timestamp */
2ad8416d 168 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
02b59d57 169
52433f6b 170 r = netdev_load(m);
02b59d57
TG
171 if (r < 0)
172 return r;
173
174 r = network_load(m);
175 if (r < 0)
176 return r;
177
178 return 0;
179}
180
181bool manager_should_reload(Manager *m) {
2ad8416d 182 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
02b59d57
TG
183}
184
f579559b 185static int manager_process_link(Manager *m, struct udev_device *device) {
11a7f229 186 Link *link = NULL;
f579559b
TG
187 int r;
188
11a7f229
TG
189 assert(m);
190 assert(device);
f579559b 191
11a7f229
TG
192 link_get(m, udev_device_get_ifindex(device), &link);
193
194 if (streq_ptr(udev_device_get_action(device), "remove")) {
449f7554 195 log_debug("%s: link removed", udev_device_get_sysname(device));
002f5de9 196
11a7f229
TG
197 if (link)
198 link_free(link);
199 } else {
200 if (link) {
201 log_debug("%s: link already exists, ignoring",
202 link->ifname);
f579559b 203 return 0;
11a7f229 204 }
f579559b 205
aa3437a5 206 r = link_add(m, device, &link);
f579559b 207 if (r < 0) {
11a7f229
TG
208 log_error("%s: could not handle link: %s",
209 udev_device_get_sysname(device),
210 strerror(-r));
2672953b 211 } else
aa3437a5
TG
212 log_debug("%s: link (with ifindex %" PRIu64") added",
213 link->ifname, link->ifindex);
f579559b
TG
214 }
215
216 return 0;
217}
218
219int manager_udev_enumerate_links(Manager *m) {
bf5332d2 220 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
f579559b 221 struct udev_list_entry *item = NULL, *first = NULL;
f579559b
TG
222 int r;
223
224 assert(m);
225
226 e = udev_enumerate_new(m->udev);
bf5332d2
LP
227 if (!e)
228 return -ENOMEM;
f579559b
TG
229
230 r = udev_enumerate_add_match_subsystem(e, "net");
231 if (r < 0)
bf5332d2 232 return r;
f579559b 233
60ad0c85
TG
234 /* udev does not initialize devices inside containers,
235 * so we rely on them being already initialized before
236 * entering the container */
237 if (detect_container(NULL) <= 0) {
238 r = udev_enumerate_add_match_is_initialized(e);
239 if (r < 0)
240 return r;
241 }
e1202047 242
f579559b
TG
243 r = udev_enumerate_scan_devices(e);
244 if (r < 0)
bf5332d2 245 return r;
f579559b
TG
246
247 first = udev_enumerate_get_list_entry(e);
248 udev_list_entry_foreach(item, first) {
bf5332d2 249 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
f579559b
TG
250 int k;
251
252 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
bf5332d2
LP
253 if (!d)
254 return -ENOMEM;
f579559b 255
bf5332d2 256 k = manager_process_link(m, d);
f579559b
TG
257 if (k < 0)
258 r = k;
259 }
260
f579559b
TG
261 return r;
262}
263
264static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
265 Manager *m = userdata;
266 struct udev_monitor *monitor = m->udev_monitor;
7b77ed8c 267 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
f579559b
TG
268
269 device = udev_monitor_receive_device(monitor);
270 if (!device)
271 return -ENOMEM;
272
7b77ed8c 273 manager_process_link(m, device);
f579559b
TG
274 return 0;
275}
276
277int manager_udev_listen(Manager *m) {
278 int r;
279
280 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
281 if (r < 0) {
282 log_error("Could not add udev monitor filter: %s", strerror(-r));
283 return r;
284 }
285
f579559b
TG
286 r = udev_monitor_enable_receiving(m->udev_monitor);
287 if (r < 0) {
288 log_error("Could not enable udev monitor");
289 return r;
290 }
291
292 r = sd_event_add_io(m->event,
151b9b96 293 &m->udev_event_source,
f579559b
TG
294 udev_monitor_get_fd(m->udev_monitor),
295 EPOLLIN, manager_dispatch_link_udev,
151b9b96 296 m);
f579559b
TG
297 if (r < 0)
298 return r;
299
300 return 0;
301}
f882c247 302
dd3efc09
TG
303static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
304 Manager *m = userdata;
305 Link *link;
50add290 306 const char *name;
dd3efc09
TG
307 int r, ifindex;
308
11a7f229
TG
309 assert(rtnl);
310 assert(message);
311 assert(m);
312
dd3efc09 313 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
50add290 314 if (r < 0 || ifindex <= 0) {
d0d311d6 315 log_debug("received RTM_NEWLINK message without valid ifindex");
dd3efc09 316 return 0;
d0d311d6 317 }
dd3efc09 318
50add290
TG
319 r = rtnl_message_link_get_ifname(message, &name);
320 if (r < 0)
321 log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME");
322 else {
1a436809 323 NetDev *netdev;
50add290
TG
324
325 r = netdev_get(m, name, &netdev);
326 if (r >= 0) {
327 r = netdev_set_ifindex(netdev, ifindex);
328 if (r < 0)
329 log_debug("could not set ifindex of netdev '%s' to %d: %s",
330 name, ifindex, strerror(-r));
331 }
332 }
333
11a7f229
TG
334 r = link_get(m, ifindex, &link);
335 if (r < 0) {
8b264404 336 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
dd3efc09 337 return 0;
d0d311d6 338 }
dd3efc09 339
06a6e593
TG
340 /* only track the status of links we want to manage */
341 if (link->network) {
342 r = link_update(link, message);
343 if (r < 0)
344 return 0;
d0d311d6 345 } else
8b264404 346 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
dd3efc09
TG
347
348 return 1;
349}
350
f882c247
TG
351int manager_rtnl_listen(Manager *m) {
352 int r;
353
354 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
355 if (r < 0)
356 return r;
357
dd3efc09
TG
358 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
359 if (r < 0)
360 return r;
361
f882c247
TG
362 return 0;
363}
3bef724f 364
1346b1f0
TG
365int manager_bus_listen(Manager *m) {
366 int r;
367
bcbca829
TG
368 assert(m->event);
369
370 if (!m->bus) /* TODO: drop when we can rely on kdbus */
371 return 0;
372
1346b1f0
TG
373 r = sd_bus_attach_event(m->bus, m->event, 0);
374 if (r < 0)
375 return r;
376
377 return 0;
378}
379
3bef724f
TG
380static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
381 char buf[INET6_ADDRSTRLEN];
382 const char *address;
383
384 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
385 if (!address) {
386 log_warning("Invalid DNS address. Ignoring.");
387 return;
388 }
389
390 if (*count == MAXNS)
f3621dec
TG
391 fputs("# Too many DNS servers configured, the following entries "
392 "will be ignored\n", f);
3bef724f
TG
393
394 fprintf(f, "nameserver %s\n", address);
395
396 (*count) ++;
397}
398
399int manager_update_resolv_conf(Manager *m) {
400 _cleanup_free_ char *temp_path = NULL;
401 _cleanup_fclose_ FILE *f = NULL;
402 Link *link;
403 Iterator i;
404 unsigned count = 0;
039ebe6a 405 const char *domainname = NULL;
3bef724f
TG
406 int r;
407
408 assert(m);
409
410 r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
411 if (r < 0)
412 return r;
413
414 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
415 if (r < 0)
416 return r;
417
418 fchmod(fileno(f), 0644);
419
b2ad8a16
TG
420 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
421 "# Third party programs must not access this file directly, but\n"
422 "# only through the symlink at /etc/resolv.conf. To manage\n"
423 "# resolv.conf(5) in a different way, replace the symlink by a\n"
424 "# static file or a different symlink.\n\n", f);
3bef724f
TG
425
426 HASHMAP_FOREACH(link, m->links, i) {
a6cc569e 427 if (link->dhcp_lease) {
7ae4ef6d
TG
428 struct in_addr *nameservers;
429 size_t nameservers_size;
3bef724f 430
039ebe6a 431 if (link->network->dhcp_dns) {
a6cc569e 432 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
039ebe6a
TG
433 if (r >= 0) {
434 unsigned j;
3bef724f 435
039ebe6a
TG
436 for (j = 0; j < nameservers_size; j++)
437 append_dns(f, &nameservers[j], AF_INET, &count);
438 }
439 }
440
441 if (link->network->dhcp_domainname && !domainname) {
a6cc569e 442 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
039ebe6a
TG
443 if (r >= 0)
444 fprintf(f, "domain %s\n", domainname);
3bef724f
TG
445 }
446 }
447 }
448
449 HASHMAP_FOREACH(link, m->links, i)
450 if (link->network && link->network->dns)
451 append_dns(f, &link->network->dns->in_addr.in,
452 link->network->dns->family, &count);
453
454 fflush(f);
455
456 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
457 r = -errno;
458 unlink("/run/systemd/network/resolv.conf");
459 unlink(temp_path);
460 return r;
461 }
462
463 return 0;
464}