]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
build-sys: properly enable the networkd dbus activation
[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
091a364c 22#include <sys/socket.h>
bbf7c048 23#include <linux/if.h>
3bef724f 24
2dcf7ec6 25#include "conf-parser.h"
f579559b
TG
26#include "path-util.h"
27#include "networkd.h"
3be1d7e0 28#include "networkd-netdev.h"
0b1831c2 29#include "networkd-link.h"
e16cb2e4 30#include "network-internal.h"
f579559b 31#include "libudev-private.h"
7b77ed8c 32#include "udev-util.h"
50add290 33#include "rtnl-util.h"
a97dcc12
TG
34#include "bus-util.h"
35#include "def.h"
3bef724f 36#include "mkdir.h"
60ad0c85 37#include "virt.h"
f579559b 38
505f8da7 39#include "sd-rtnl.h"
5544ee85 40#include "sd-daemon.h"
505f8da7 41
be660c37
AR
42/* use 8 MB for receive socket kernel queue. */
43#define RCVBUF_SIZE (8*1024*1024)
44
2ad8416d
ZJS
45const char* const network_dirs[] = {
46 "/etc/systemd/network",
47 "/run/systemd/network",
48 "/usr/lib/systemd/network",
eed0eee8 49#ifdef HAVE_SPLIT_USR
2ad8416d
ZJS
50 "/lib/systemd/network",
51#endif
52 NULL};
53
11bf3cce
LP
54static int setup_default_address_pool(Manager *m) {
55 AddressPool *p;
56 int r;
57
58 assert(m);
59
60 /* Add in the well-known private address ranges. */
61
62 r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
63 if (r < 0)
64 return r;
65
66 r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
67 if (r < 0)
68 return r;
69
70 r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
71 if (r < 0)
72 return r;
73
74 r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
75 if (r < 0)
76 return r;
77
78 return 0;
79}
80
9c0a72f9
TG
81static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
82 Manager *m = userdata;
83
84 assert(s);
85 assert(m);
86
87 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
88
89 manager_connect_bus(m);
90
91 return 0;
92}
93
94static int manager_reset_all(Manager *m) {
95 Link *link;
96 Iterator i;
97 int r;
98
99 assert(m);
100
101 HASHMAP_FOREACH(link, m->links, i) {
102 r = link_carrier_reset(link);
103 if (r < 0)
104 log_link_warning_errno(link, r, "could not reset carrier: %m");
105 }
106
107 return 0;
108}
109
110static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
111 Manager *m = userdata;
112 int b, r;
113
114 assert(bus);
115 assert(bus);
116
117 r = sd_bus_message_read(message, "b", &b);
118 if (r < 0) {
119 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
120 return 0;
121 }
122
123 if (b)
124 return 0;
125
126 log_debug("Coming back from suspend, resetting all connections...");
127
128 manager_reset_all(m);
129
130 return 0;
131}
132
133int manager_connect_bus(Manager *m) {
134 int r;
135
136 assert(m);
137
138 r = sd_bus_default_system(&m->bus);
139 if (r == -ENOENT) {
140 /* We failed to connect? Yuck, we must be in early
141 * boot. Let's try in 5s again. As soon as we have
142 * kdbus we can stop doing this... */
143
144 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
145
146 r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
147 if (r < 0)
148 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
149
150 return 0;
151 } if (r < 0)
152 return r;
153
9c0a72f9
TG
154 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
155 "type='signal',"
156 "sender='org.freedesktop.login1',"
157 "interface='org.freedesktop.login1.Manager',"
158 "member='PrepareForSleep',"
159 "path='/org/freedesktop/login1'",
160 match_prepare_for_sleep,
161 m);
162 if (r < 0)
163 return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
164
e331e246
TG
165 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
166 if (r < 0)
167 return log_error_errno(r, "Failed to add manager object vtable: %m");
168
169 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
170 if (r < 0)
171 return log_error_errno(r, "Failed to add link object vtable: %m");
172
173 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
174 if (r < 0)
175 return log_error_errno(r, "Failed to add link enumerator: %m");
176
177 r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
178 if (r < 0)
179 return log_error_errno(r, "Failed to register name: %m");
180
181 r = sd_bus_attach_event(m->bus, m->event, 0);
182 if (r < 0)
183 return log_error_errno(r, "Failed to attach bus to event loop: %m");
184
9c0a72f9
TG
185 return 0;
186}
187
5fae368b
TG
188static int manager_udev_process_link(Manager *m, struct udev_device *device) {
189 Link *link = NULL;
190 int r, ifindex;
5544ee85 191
5fae368b
TG
192 assert(m);
193 assert(device);
5544ee85 194
5fae368b
TG
195 if (!streq_ptr(udev_device_get_action(device), "add"))
196 return 0;
5544ee85 197
5fae368b
TG
198 ifindex = udev_device_get_ifindex(device);
199 if (ifindex <= 0) {
200 log_debug("ignoring udev ADD event for device with invalid ifindex");
201 return 0;
5544ee85
TG
202 }
203
5fae368b
TG
204 r = link_get(m, ifindex, &link);
205 if (r == -ENODEV)
206 return 0;
207 else if (r < 0)
f579559b
TG
208 return r;
209
5fae368b 210 r = link_initialized(link, device);
44de0efc
LP
211 if (r < 0)
212 return r;
213
5fae368b
TG
214 return 0;
215}
be660c37 216
5fae368b
TG
217static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
218 Manager *m = userdata;
219 struct udev_monitor *monitor = m->udev_monitor;
220 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
f579559b 221
5fae368b
TG
222 device = udev_monitor_receive_device(monitor);
223 if (!device)
02b59d57
TG
224 return -ENOMEM;
225
5fae368b 226 manager_udev_process_link(m, device);
f579559b
TG
227 return 0;
228}
229
5fae368b
TG
230static int manager_connect_udev(Manager *m) {
231 int r;
f579559b 232
5fae368b
TG
233 /* udev does not initialize devices inside containers,
234 * so we rely on them being already initialized before
235 * entering the container */
236 if (detect_container(NULL) > 0)
237 return 0;
f579559b 238
5fae368b
TG
239 m->udev = udev_new();
240 if (!m->udev)
241 return -ENOMEM;
02b59d57 242
5fae368b
TG
243 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
244 if (!m->udev_monitor)
245 return -ENOMEM;
02b59d57 246
5fae368b 247 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
02b59d57 248 if (r < 0)
5fae368b 249 return log_error_errno(r, "Could not add udev monitor filter: %m");
02b59d57 250
5fae368b
TG
251 r = udev_monitor_enable_receiving(m->udev_monitor);
252 if (r < 0) {
253 log_error("Could not enable udev monitor");
02b59d57 254 return r;
667fcc6d 255 }
505f8da7 256
5fae368b
TG
257 r = sd_event_add_io(m->event,
258 &m->udev_event_source,
259 udev_monitor_get_fd(m->udev_monitor),
260 EPOLLIN, manager_dispatch_link_udev,
261 m);
262 if (r < 0)
667fcc6d 263 return r;
505f8da7 264
5fae368b 265 r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
505f8da7
TG
266 if (r < 0)
267 return r;
11a7f229 268
505f8da7
TG
269 return 0;
270}
f579559b 271
505f8da7
TG
272static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
273 Manager *m = userdata;
274 Link *link = NULL;
4d473d5d 275 NetDev *netdev = NULL;
f2236469 276 uint16_t type;
ca4e095a 277 const char *name;
505f8da7 278 int r, ifindex;
f579559b 279
505f8da7
TG
280 assert(rtnl);
281 assert(message);
f579559b
TG
282 assert(m);
283
45af44d4
TG
284 if (sd_rtnl_message_is_error(message)) {
285 r = sd_rtnl_message_get_errno(message);
286 if (r < 0)
287 log_warning_errno(r, "rtnl: could not receive link: %m");
288
289 return 0;
290 }
291
f2236469
TG
292 r = sd_rtnl_message_get_type(message, &type);
293 if (r < 0) {
45af44d4 294 log_warning_errno(r, "rtnl: could not get message type: %m");
f2236469
TG
295 return 0;
296 }
297
505f8da7 298 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
45af44d4
TG
299 if (r < 0) {
300 log_warning_errno(r, "rtnl: could not get ifindex: %m");
301 return 0;
302 } else if (ifindex <= 0) {
303 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
505f8da7 304 return 0;
4d473d5d
TG
305 } else
306 link_get(m, ifindex, &link);
f579559b 307
505f8da7 308 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
45af44d4
TG
309 if (r < 0) {
310 log_warning_errno(r, "rtnl: received link message without ifname: %m");
4d473d5d
TG
311 return 0;
312 } else
f2236469 313 netdev_get(m, name, &netdev);
4d473d5d
TG
314
315 switch (type) {
316 case RTM_NEWLINK:
317 if (!link) {
318 /* link is new, so add it */
319 r = link_add(m, message, &link);
320 if (r < 0) {
17d1f37d 321 log_warning_errno(r, "could not add new link: %m");
4d473d5d
TG
322 return 0;
323 }
324 }
325
326 if (netdev) {
327 /* netdev exists, so make sure the ifindex matches */
505f8da7
TG
328 r = netdev_set_ifindex(netdev, message);
329 if (r < 0) {
17d1f37d 330 log_warning_errno(r, "could not set ifindex on netdev: %m");
505f8da7
TG
331 return 0;
332 }
333 }
e1202047 334
f2236469
TG
335 r = link_update(link, message);
336 if (r < 0)
337 return 0;
4d473d5d
TG
338
339 break;
340
341 case RTM_DELLINK:
342 link_drop(link);
343 netdev_drop(netdev);
344
345 break;
346
347 default:
348 assert_not_reached("Received invalid RTNL message type.");
f2236469 349 }
505f8da7
TG
350
351 return 1;
352}
353
5fae368b
TG
354static int systemd_netlink_fd(void) {
355 int n, fd, rtnl_fd = -EINVAL;
356
357 n = sd_listen_fds(true);
358 if (n <= 0)
359 return -EINVAL;
360
361 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
362 if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
363 if (rtnl_fd >= 0)
364 return -EINVAL;
365
366 rtnl_fd = fd;
367 }
368 }
369
370 return rtnl_fd;
371}
372
373static int manager_connect_rtnl(Manager *m) {
374 int fd, r;
505f8da7
TG
375
376 assert(m);
505f8da7 377
5fae368b
TG
378 fd = systemd_netlink_fd();
379 if (fd < 0)
380 r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
381 else
382 r = sd_rtnl_open_fd(&m->rtnl, fd, 0);
505f8da7
TG
383 if (r < 0)
384 return r;
385
5fae368b 386 r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
f579559b 387 if (r < 0)
bf5332d2 388 return r;
f579559b 389
5fae368b 390 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
505f8da7
TG
391 if (r < 0)
392 return r;
f579559b 393
5fae368b
TG
394 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
395 if (r < 0)
396 return r;
505f8da7 397
5fae368b
TG
398 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
399 if (r < 0)
400 return r;
45af44d4 401
5fae368b
TG
402 r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
403 if (r < 0)
404 return r;
405
406 r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
407 if (r < 0)
408 return r;
409
410 return 0;
45af44d4 411}
505f8da7 412
5fae368b
TG
413int manager_new(Manager **ret) {
414 _cleanup_manager_free_ Manager *m = NULL;
45af44d4 415 int r;
f579559b 416
5fae368b
TG
417 m = new0(Manager, 1);
418 if (!m)
419 return -ENOMEM;
45af44d4 420
5fae368b
TG
421 m->state_file = strdup("/run/systemd/netif/state");
422 if (!m->state_file)
423 return -ENOMEM;
424
425 r = sd_event_default(&m->event);
45af44d4
TG
426 if (r < 0)
427 return r;
428
5fae368b
TG
429 sd_event_set_watchdog(m->event, true);
430
431 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
432 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
433
434 r = manager_connect_rtnl(m);
45af44d4
TG
435 if (r < 0)
436 return r;
437
5fae368b
TG
438 r = manager_connect_udev(m);
439 if (r < 0)
440 return r;
45af44d4 441
5fae368b
TG
442 m->netdevs = hashmap_new(&string_hash_ops);
443 if (!m->netdevs)
444 return -ENOMEM;
f579559b 445
5fae368b 446 LIST_HEAD_INIT(m->networks);
f579559b 447
5fae368b
TG
448 r = setup_default_address_pool(m);
449 if (r < 0)
450 return r;
f579559b 451
5fae368b
TG
452 *ret = m;
453 m = NULL;
f579559b 454
f579559b
TG
455 return 0;
456}
457
5fae368b
TG
458void manager_free(Manager *m) {
459 Network *network;
460 NetDev *netdev;
461 Link *link;
462 AddressPool *pool;
f579559b 463
5fae368b
TG
464 if (!m)
465 return;
505f8da7 466
5fae368b 467 free(m->state_file);
505f8da7 468
5fae368b
TG
469 udev_monitor_unref(m->udev_monitor);
470 udev_unref(m->udev);
471 sd_bus_unref(m->bus);
472 sd_bus_slot_unref(m->prepare_for_sleep_slot);
473 sd_event_source_unref(m->udev_event_source);
474 sd_event_source_unref(m->bus_retry_event_source);
475 sd_event_unref(m->event);
f579559b 476
5fae368b
TG
477 while ((link = hashmap_first(m->links)))
478 link_unref(link);
479 hashmap_free(m->links);
f579559b 480
5fae368b
TG
481 while ((network = m->networks))
482 network_free(network);
483
484 while ((netdev = hashmap_first(m->netdevs)))
485 netdev_unref(netdev);
486 hashmap_free(m->netdevs);
487
488 while ((pool = m->address_pools))
489 address_pool_free(pool);
490
491 sd_rtnl_unref(m->rtnl);
492
493 free(m);
494}
495
a97dcc12
TG
496static bool manager_check_idle(void *userdata) {
497 Manager *m = userdata;
498 Link *link;
499 Iterator i;
500
501 assert(m);
502
503 HASHMAP_FOREACH(link, m->links, i) {
504 /* we are not woken on udev activity, so let's just wait for the
505 * pending udev event */
506 if (link->state == LINK_STATE_PENDING)
507 return false;
508
509 if (!link->network)
510 continue;
511
512 /* we are not woken on netork activity, so let's stay around */
513 if (link_lldp_enabled(link) ||
514 link_ipv4ll_enabled(link) ||
515 link_dhcp4_server_enabled(link) ||
516 link_dhcp4_enabled(link) ||
517 link_dhcp6_enabled(link))
518 return false;
519 }
520
521 return true;
522}
523
524int manager_run(Manager *m) {
525 assert(m);
526
527 return bus_event_loop_with_idle(
528 m->event,
529 m->bus,
530 "org.freedesktop.network1",
531 DEFAULT_EXIT_USEC,
532 manager_check_idle,
533 m);
534}
535
5fae368b
TG
536int manager_load_config(Manager *m) {
537 int r;
538
539 /* update timestamp */
540 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
541
542 r = netdev_load(m);
f579559b
TG
543 if (r < 0)
544 return r;
545
5fae368b 546 r = network_load(m);
9021bb9f
TG
547 if (r < 0)
548 return r;
549
f579559b
TG
550 return 0;
551}
f882c247 552
5fae368b
TG
553bool manager_should_reload(Manager *m) {
554 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
555}
556
557int manager_rtnl_enumerate_links(Manager *m) {
558 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
559 sd_rtnl_message *link;
f882c247
TG
560 int r;
561
5da8149f 562 assert(m);
5fae368b 563 assert(m->rtnl);
5da8149f 564
5fae368b 565 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
f882c247
TG
566 if (r < 0)
567 return r;
568
5fae368b 569 r = sd_rtnl_message_request_dump(req, true);
dd3efc09
TG
570 if (r < 0)
571 return r;
572
5fae368b 573 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
f2236469
TG
574 if (r < 0)
575 return r;
576
5fae368b
TG
577 for (link = reply; link; link = sd_rtnl_message_next(link)) {
578 int k;
2e9f08ea 579
6a24f148
TG
580 m->enumerating = true;
581
5fae368b
TG
582 k = manager_rtnl_process_link(m->rtnl, link, m);
583 if (k < 0)
584 r = k;
6a24f148
TG
585
586 m->enumerating = false;
5fae368b 587 }
2e9f08ea 588
5fae368b 589 return r;
f882c247 590}
3bef724f 591
5fae368b
TG
592int manager_rtnl_enumerate_addresses(Manager *m) {
593 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
594 sd_rtnl_message *addr;
1346b1f0
TG
595 int r;
596
5fae368b
TG
597 assert(m);
598 assert(m->rtnl);
bcbca829 599
5fae368b
TG
600 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
601 if (r < 0)
602 return r;
bcbca829 603
5fae368b 604 r = sd_rtnl_message_request_dump(req, true);
1346b1f0
TG
605 if (r < 0)
606 return r;
607
5fae368b
TG
608 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
609 if (r < 0)
610 return r;
611
612 for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
613 int k;
614
6a24f148
TG
615 m->enumerating = true;
616
5fae368b
TG
617 k = link_rtnl_process_address(m->rtnl, addr, m);
618 if (k < 0)
619 r = k;
6a24f148
TG
620
621 m->enumerating = false;
5fae368b
TG
622 }
623
624 return r;
1346b1f0
TG
625}
626
c0c743cb
LP
627static int set_put_in_addr(Set *s, const struct in_addr *address) {
628 char *p;
629 int r;
630
631 assert(s);
632
633 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
634 if (r < 0)
635 return r;
636
637 r = set_consume(s, p);
638 if (r == -EEXIST)
639 return 0;
640
641 return r;
642}
643
644static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
645 int r, i, c = 0;
646
647 assert(s);
648 assert(n <= 0 || addresses);
649
650 for (i = 0; i < n; i++) {
651 r = set_put_in_addr(s, addresses+i);
652 if (r < 0)
653 return r;
654
655 c += r;
656 }
657
658 return c;
659}
660
8612e936
LP
661static void print_string_set(FILE *f, const char *field, Set *s) {
662 bool space = false;
663 Iterator i;
664 char *p;
665
666 if (set_isempty(s))
667 return;
668
669 fputs(field, f);
670
671 SET_FOREACH(p, s, i) {
672 if (space)
673 fputc(' ', f);
674 fputs(p, f);
675 space = true;
676 }
677 fputc('\n', f);
678}
679
bbf7c048 680int manager_save(Manager *m) {
8612e936 681 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
bbf7c048
TG
682 Link *link;
683 Iterator i;
684 _cleanup_free_ char *temp_path = NULL;
685 _cleanup_fclose_ FILE *f = NULL;
d3df0e39 686 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
e375dcde 687 const char *operstate_str;
bbf7c048
TG
688 int r;
689
690 assert(m);
691 assert(m->state_file);
692
c0c743cb 693 /* We add all NTP and DNS server to a set, to filter out duplicates */
d5099efc 694 dns = set_new(&string_hash_ops);
c0c743cb
LP
695 if (!dns)
696 return -ENOMEM;
697
d5099efc 698 ntp = set_new(&string_hash_ops);
c0c743cb
LP
699 if (!ntp)
700 return -ENOMEM;
701
d5099efc 702 domains = set_new(&string_hash_ops);
8612e936
LP
703 if (!domains)
704 return -ENOMEM;
705
bbf7c048
TG
706 HASHMAP_FOREACH(link, m->links, i) {
707 if (link->flags & IFF_LOOPBACK)
708 continue;
709
e375dcde
TG
710 if (link->operstate > operstate)
711 operstate = link->operstate;
c0c743cb
LP
712
713 if (!link->network)
714 continue;
715
716 /* First add the static configured entries */
717 r = set_put_strdupv(dns, link->network->dns);
718 if (r < 0)
719 return r;
720
721 r = set_put_strdupv(ntp, link->network->ntp);
722 if (r < 0)
723 return r;
724
8612e936
LP
725 r = set_put_strdupv(domains, link->network->domains);
726 if (r < 0)
727 return r;
728
c0c743cb
LP
729 if (!link->dhcp_lease)
730 continue;
731
732 /* Secondly, add the entries acquired via DHCP */
733 if (link->network->dhcp_dns) {
734 const struct in_addr *addresses;
735
736 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
737 if (r > 0) {
738 r = set_put_in_addrv(dns, addresses, r);
739 if (r < 0)
740 return r;
8612e936 741 } else if (r < 0 && r != -ENOENT)
c0c743cb
LP
742 return r;
743 }
744
745 if (link->network->dhcp_ntp) {
746 const struct in_addr *addresses;
747
748 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
749 if (r > 0) {
750 r = set_put_in_addrv(ntp, addresses, r);
751 if (r < 0)
752 return r;
8612e936
LP
753 } else if (r < 0 && r != -ENOENT)
754 return r;
755 }
756
757 if (link->network->dhcp_domains) {
758 const char *domainname;
759
760 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
761 if (r >= 0) {
762 r = set_put_strdup(domains, domainname);
763 if (r < 0)
764 return r;
c0c743cb
LP
765 } else if (r != -ENOENT)
766 return r;
767 }
bbf7c048
TG
768 }
769
e375dcde
TG
770 operstate_str = link_operstate_to_string(operstate);
771 assert(operstate_str);
bbf7c048
TG
772
773 r = fopen_temporary(m->state_file, &f, &temp_path);
774 if (r < 0)
c2d6bd61 775 return r;
bbf7c048
TG
776
777 fchmod(fileno(f), 0644);
778
779 fprintf(f,
780 "# This is private data. Do not parse.\n"
e375dcde 781 "OPER_STATE=%s\n", operstate_str);
bbf7c048 782
8612e936
LP
783 print_string_set(f, "DNS=", dns);
784 print_string_set(f, "NTP=", ntp);
785 print_string_set(f, "DOMAINS=", domains);
c0c743cb 786
c2d6bd61
LP
787 r = fflush_and_check(f);
788 if (r < 0)
789 goto fail;
bbf7c048 790
c2d6bd61 791 if (rename(temp_path, m->state_file) < 0) {
bbf7c048 792 r = -errno;
c2d6bd61 793 goto fail;
bbf7c048
TG
794 }
795
e331e246
TG
796 if (m->operational_state != operstate) {
797 m->operational_state = operstate;
798 r = manager_send_changed(m, "OperationalState", NULL);
799 if (r < 0)
800 log_error_errno(r, "Could not emit changed OperationalState: %m");
801 }
802
c2d6bd61 803 return 0;
bbf7c048 804
c2d6bd61 805fail:
da927ba9 806 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
c2d6bd61
LP
807 unlink(m->state_file);
808 unlink(temp_path);
bbf7c048
TG
809 return r;
810}
11bf3cce 811
0dd25fb9 812int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce
LP
813 AddressPool *p;
814 int r;
815
816 assert(m);
817 assert(prefixlen > 0);
818 assert(found);
819
820 LIST_FOREACH(address_pools, p, m->address_pools) {
821 if (p->family != family)
822 continue;
823
824 r = address_pool_acquire(p, prefixlen, found);
825 if (r != 0)
826 return r;
827 }
828
829 return 0;
830}
cb9fc36a
LP
831
832const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
833 if (b == ADDRESS_FAMILY_YES ||
834 b == ADDRESS_FAMILY_NO)
835 return yes_no(b == ADDRESS_FAMILY_YES);
836
837 if (b == ADDRESS_FAMILY_IPV4)
838 return "ipv4";
839 if (b == ADDRESS_FAMILY_IPV6)
840 return "ipv6";
841
842 return NULL;
843}
844
845AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
846 int r;
847
848 /* Make this a true superset of a boolean */
849
850 r = parse_boolean(s);
851 if (r > 0)
852 return ADDRESS_FAMILY_YES;
853 if (r == 0)
854 return ADDRESS_FAMILY_NO;
855
856 if (streq(s, "ipv4"))
857 return ADDRESS_FAMILY_IPV4;
858 if (streq(s, "ipv6"))
859 return ADDRESS_FAMILY_IPV6;
860
861 return _ADDRESS_FAMILY_BOOLEAN_INVALID;
862}
769d324c
LP
863
864DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");