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