]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
nss-myhostname: port to sd-rtnl
[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",
eed0eee8 36#ifdef HAVE_SPLIT_USR
2ad8416d
ZJS
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 147
0617ffab
TG
148 while ((link = hashmap_first(m->links)))
149 link_free(link);
f579559b 150 hashmap_free(m->links);
0617ffab 151
2292547a
TG
152 while ((network = m->networks))
153 network_free(network);
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;
d22f1006 306 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) {
c49b33ac 315 log_warning("received RTM_NEWLINK message without valid ifindex");
dd3efc09 316 return 0;
d0d311d6 317 }
dd3efc09 318
d22f1006 319 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
50add290 320 if (r < 0)
c49b33ac 321 log_warning("received RTM_NEWLINK message without valid ifname");
50add290 322 else {
1a436809 323 NetDev *netdev;
50add290
TG
324
325 r = netdev_get(m, name, &netdev);
20861203 326 if (r >= 0) {
ba5596ec 327 netdev_set_ifindex(netdev, message);
20861203
TG
328 r = sd_rtnl_message_rewind(message);
329 if (r < 0) {
330 log_debug("could not rewind rtnl message");
331 return 0;
332 }
333 }
50add290
TG
334 }
335
11a7f229
TG
336 r = link_get(m, ifindex, &link);
337 if (r < 0) {
8b264404 338 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
dd3efc09 339 return 0;
d0d311d6 340 }
dd3efc09 341
06a6e593
TG
342 /* only track the status of links we want to manage */
343 if (link->network) {
344 r = link_update(link, message);
345 if (r < 0)
346 return 0;
d0d311d6 347 } else
8b264404 348 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
dd3efc09
TG
349
350 return 1;
351}
352
f882c247
TG
353int manager_rtnl_listen(Manager *m) {
354 int r;
355
356 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
357 if (r < 0)
358 return r;
359
dd3efc09
TG
360 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
361 if (r < 0)
362 return r;
363
f882c247
TG
364 return 0;
365}
3bef724f 366
1346b1f0
TG
367int manager_bus_listen(Manager *m) {
368 int r;
369
bcbca829
TG
370 assert(m->event);
371
372 if (!m->bus) /* TODO: drop when we can rely on kdbus */
373 return 0;
374
1346b1f0
TG
375 r = sd_bus_attach_event(m->bus, m->event, 0);
376 if (r < 0)
377 return r;
378
379 return 0;
380}
381
3bef724f
TG
382static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
383 char buf[INET6_ADDRSTRLEN];
384 const char *address;
385
386 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
387 if (!address) {
388 log_warning("Invalid DNS address. Ignoring.");
389 return;
390 }
391
392 if (*count == MAXNS)
f3621dec
TG
393 fputs("# Too many DNS servers configured, the following entries "
394 "will be ignored\n", f);
3bef724f
TG
395
396 fprintf(f, "nameserver %s\n", address);
397
398 (*count) ++;
399}
400
401int manager_update_resolv_conf(Manager *m) {
402 _cleanup_free_ char *temp_path = NULL;
403 _cleanup_fclose_ FILE *f = NULL;
404 Link *link;
405 Iterator i;
406 unsigned count = 0;
039ebe6a 407 const char *domainname = NULL;
3bef724f
TG
408 int r;
409
410 assert(m);
411
3bef724f
TG
412 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
413 if (r < 0)
414 return r;
415
416 fchmod(fileno(f), 0644);
417
b2ad8a16
TG
418 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
419 "# Third party programs must not access this file directly, but\n"
420 "# only through the symlink at /etc/resolv.conf. To manage\n"
421 "# resolv.conf(5) in a different way, replace the symlink by a\n"
422 "# static file or a different symlink.\n\n", f);
3bef724f
TG
423
424 HASHMAP_FOREACH(link, m->links, i) {
a6cc569e 425 if (link->dhcp_lease) {
7ae4ef6d
TG
426 struct in_addr *nameservers;
427 size_t nameservers_size;
3bef724f 428
039ebe6a 429 if (link->network->dhcp_dns) {
a6cc569e 430 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
039ebe6a
TG
431 if (r >= 0) {
432 unsigned j;
3bef724f 433
039ebe6a
TG
434 for (j = 0; j < nameservers_size; j++)
435 append_dns(f, &nameservers[j], AF_INET, &count);
436 }
437 }
438
439 if (link->network->dhcp_domainname && !domainname) {
a6cc569e 440 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
039ebe6a
TG
441 if (r >= 0)
442 fprintf(f, "domain %s\n", domainname);
3bef724f
TG
443 }
444 }
445 }
446
06f021a8
TG
447 HASHMAP_FOREACH(link, m->links, i) {
448 if (link->network && link->network->dns) {
449 Address *address;
450 Iterator j;
451
452 SET_FOREACH(address, link->network->dns, j) {
453 append_dns(f, &address->in_addr.in,
454 address->family, &count);
455 }
456 }
457 }
3bef724f
TG
458
459 fflush(f);
460
461 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
462 r = -errno;
463 unlink("/run/systemd/network/resolv.conf");
464 unlink(temp_path);
465 return r;
466 }
467
468 return 0;
469}