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