]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
networkd: don't unlink state files on exit
[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"
3bef724f 34#include "mkdir.h"
60ad0c85 35#include "virt.h"
f579559b 36
505f8da7 37#include "sd-rtnl.h"
5544ee85 38#include "sd-daemon.h"
505f8da7 39
be660c37
AR
40/* use 8 MB for receive socket kernel queue. */
41#define RCVBUF_SIZE (8*1024*1024)
42
2ad8416d
ZJS
43const char* const network_dirs[] = {
44 "/etc/systemd/network",
45 "/run/systemd/network",
46 "/usr/lib/systemd/network",
eed0eee8 47#ifdef HAVE_SPLIT_USR
2ad8416d
ZJS
48 "/lib/systemd/network",
49#endif
50 NULL};
51
11bf3cce
LP
52static int setup_default_address_pool(Manager *m) {
53 AddressPool *p;
54 int r;
55
56 assert(m);
57
58 /* Add in the well-known private address ranges. */
59
60 r = address_pool_new_from_string(m, &p, AF_INET6, "fc00::", 7);
61 if (r < 0)
62 return r;
63
64 r = address_pool_new_from_string(m, &p, AF_INET, "192.168.0.0", 16);
65 if (r < 0)
66 return r;
67
68 r = address_pool_new_from_string(m, &p, AF_INET, "172.16.0.0", 12);
69 if (r < 0)
70 return r;
71
72 r = address_pool_new_from_string(m, &p, AF_INET, "10.0.0.0", 8);
73 if (r < 0)
74 return r;
75
76 return 0;
77}
78
9c0a72f9
TG
79int manager_connect_bus(Manager *m);
80
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 438 r = manager_connect_bus(m);
45af44d4
TG
439 if (r < 0)
440 return r;
441
5fae368b
TG
442 r = manager_connect_udev(m);
443 if (r < 0)
444 return r;
45af44d4 445
5fae368b
TG
446 m->netdevs = hashmap_new(&string_hash_ops);
447 if (!m->netdevs)
448 return -ENOMEM;
f579559b 449
5fae368b 450 LIST_HEAD_INIT(m->networks);
f579559b 451
5fae368b
TG
452 r = setup_default_address_pool(m);
453 if (r < 0)
454 return r;
f579559b 455
5fae368b
TG
456 *ret = m;
457 m = NULL;
f579559b 458
f579559b
TG
459 return 0;
460}
461
5fae368b
TG
462void manager_free(Manager *m) {
463 Network *network;
464 NetDev *netdev;
465 Link *link;
466 AddressPool *pool;
f579559b 467
5fae368b
TG
468 if (!m)
469 return;
505f8da7 470
5fae368b 471 free(m->state_file);
505f8da7 472
5fae368b
TG
473 udev_monitor_unref(m->udev_monitor);
474 udev_unref(m->udev);
475 sd_bus_unref(m->bus);
476 sd_bus_slot_unref(m->prepare_for_sleep_slot);
477 sd_event_source_unref(m->udev_event_source);
478 sd_event_source_unref(m->bus_retry_event_source);
479 sd_event_unref(m->event);
f579559b 480
5fae368b
TG
481 while ((link = hashmap_first(m->links)))
482 link_unref(link);
483 hashmap_free(m->links);
f579559b 484
5fae368b
TG
485 while ((network = m->networks))
486 network_free(network);
487
488 while ((netdev = hashmap_first(m->netdevs)))
489 netdev_unref(netdev);
490 hashmap_free(m->netdevs);
491
492 while ((pool = m->address_pools))
493 address_pool_free(pool);
494
495 sd_rtnl_unref(m->rtnl);
496
497 free(m);
498}
499
500int manager_load_config(Manager *m) {
501 int r;
502
503 /* update timestamp */
504 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
505
506 r = netdev_load(m);
f579559b
TG
507 if (r < 0)
508 return r;
509
5fae368b 510 r = network_load(m);
9021bb9f
TG
511 if (r < 0)
512 return r;
513
f579559b
TG
514 return 0;
515}
f882c247 516
5fae368b
TG
517bool manager_should_reload(Manager *m) {
518 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
519}
520
521int manager_rtnl_enumerate_links(Manager *m) {
522 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
523 sd_rtnl_message *link;
f882c247
TG
524 int r;
525
5da8149f 526 assert(m);
5fae368b 527 assert(m->rtnl);
5da8149f 528
5fae368b 529 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
f882c247
TG
530 if (r < 0)
531 return r;
532
5fae368b 533 r = sd_rtnl_message_request_dump(req, true);
dd3efc09
TG
534 if (r < 0)
535 return r;
536
5fae368b 537 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
f2236469
TG
538 if (r < 0)
539 return r;
540
5fae368b
TG
541 for (link = reply; link; link = sd_rtnl_message_next(link)) {
542 int k;
2e9f08ea 543
6a24f148
TG
544 m->enumerating = true;
545
5fae368b
TG
546 k = manager_rtnl_process_link(m->rtnl, link, m);
547 if (k < 0)
548 r = k;
6a24f148
TG
549
550 m->enumerating = false;
5fae368b 551 }
2e9f08ea 552
5fae368b 553 return r;
f882c247 554}
3bef724f 555
5fae368b
TG
556int manager_rtnl_enumerate_addresses(Manager *m) {
557 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
558 sd_rtnl_message *addr;
1346b1f0
TG
559 int r;
560
5fae368b
TG
561 assert(m);
562 assert(m->rtnl);
bcbca829 563
5fae368b
TG
564 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
565 if (r < 0)
566 return r;
bcbca829 567
5fae368b 568 r = sd_rtnl_message_request_dump(req, true);
1346b1f0
TG
569 if (r < 0)
570 return r;
571
5fae368b
TG
572 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
573 if (r < 0)
574 return r;
575
576 for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
577 int k;
578
6a24f148
TG
579 m->enumerating = true;
580
5fae368b
TG
581 k = link_rtnl_process_address(m->rtnl, addr, m);
582 if (k < 0)
583 r = k;
6a24f148
TG
584
585 m->enumerating = false;
5fae368b
TG
586 }
587
588 return r;
1346b1f0
TG
589}
590
c0c743cb
LP
591static int set_put_in_addr(Set *s, const struct in_addr *address) {
592 char *p;
593 int r;
594
595 assert(s);
596
597 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
598 if (r < 0)
599 return r;
600
601 r = set_consume(s, p);
602 if (r == -EEXIST)
603 return 0;
604
605 return r;
606}
607
608static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
609 int r, i, c = 0;
610
611 assert(s);
612 assert(n <= 0 || addresses);
613
614 for (i = 0; i < n; i++) {
615 r = set_put_in_addr(s, addresses+i);
616 if (r < 0)
617 return r;
618
619 c += r;
620 }
621
622 return c;
623}
624
8612e936
LP
625static void print_string_set(FILE *f, const char *field, Set *s) {
626 bool space = false;
627 Iterator i;
628 char *p;
629
630 if (set_isempty(s))
631 return;
632
633 fputs(field, f);
634
635 SET_FOREACH(p, s, i) {
636 if (space)
637 fputc(' ', f);
638 fputs(p, f);
639 space = true;
640 }
641 fputc('\n', f);
642}
643
bbf7c048 644int manager_save(Manager *m) {
8612e936 645 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
bbf7c048
TG
646 Link *link;
647 Iterator i;
648 _cleanup_free_ char *temp_path = NULL;
649 _cleanup_fclose_ FILE *f = NULL;
d3df0e39 650 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
e375dcde 651 const char *operstate_str;
bbf7c048
TG
652 int r;
653
654 assert(m);
655 assert(m->state_file);
656
c0c743cb 657 /* We add all NTP and DNS server to a set, to filter out duplicates */
d5099efc 658 dns = set_new(&string_hash_ops);
c0c743cb
LP
659 if (!dns)
660 return -ENOMEM;
661
d5099efc 662 ntp = set_new(&string_hash_ops);
c0c743cb
LP
663 if (!ntp)
664 return -ENOMEM;
665
d5099efc 666 domains = set_new(&string_hash_ops);
8612e936
LP
667 if (!domains)
668 return -ENOMEM;
669
bbf7c048
TG
670 HASHMAP_FOREACH(link, m->links, i) {
671 if (link->flags & IFF_LOOPBACK)
672 continue;
673
e375dcde
TG
674 if (link->operstate > operstate)
675 operstate = link->operstate;
c0c743cb
LP
676
677 if (!link->network)
678 continue;
679
680 /* First add the static configured entries */
681 r = set_put_strdupv(dns, link->network->dns);
682 if (r < 0)
683 return r;
684
685 r = set_put_strdupv(ntp, link->network->ntp);
686 if (r < 0)
687 return r;
688
8612e936
LP
689 r = set_put_strdupv(domains, link->network->domains);
690 if (r < 0)
691 return r;
692
c0c743cb
LP
693 if (!link->dhcp_lease)
694 continue;
695
696 /* Secondly, add the entries acquired via DHCP */
697 if (link->network->dhcp_dns) {
698 const struct in_addr *addresses;
699
700 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
701 if (r > 0) {
702 r = set_put_in_addrv(dns, addresses, r);
703 if (r < 0)
704 return r;
8612e936 705 } else if (r < 0 && r != -ENOENT)
c0c743cb
LP
706 return r;
707 }
708
709 if (link->network->dhcp_ntp) {
710 const struct in_addr *addresses;
711
712 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
713 if (r > 0) {
714 r = set_put_in_addrv(ntp, addresses, r);
715 if (r < 0)
716 return r;
8612e936
LP
717 } else if (r < 0 && r != -ENOENT)
718 return r;
719 }
720
721 if (link->network->dhcp_domains) {
722 const char *domainname;
723
724 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
725 if (r >= 0) {
726 r = set_put_strdup(domains, domainname);
727 if (r < 0)
728 return r;
c0c743cb
LP
729 } else if (r != -ENOENT)
730 return r;
731 }
bbf7c048
TG
732 }
733
e375dcde
TG
734 operstate_str = link_operstate_to_string(operstate);
735 assert(operstate_str);
bbf7c048
TG
736
737 r = fopen_temporary(m->state_file, &f, &temp_path);
738 if (r < 0)
c2d6bd61 739 return r;
bbf7c048
TG
740
741 fchmod(fileno(f), 0644);
742
743 fprintf(f,
744 "# This is private data. Do not parse.\n"
e375dcde 745 "OPER_STATE=%s\n", operstate_str);
bbf7c048 746
8612e936
LP
747 print_string_set(f, "DNS=", dns);
748 print_string_set(f, "NTP=", ntp);
749 print_string_set(f, "DOMAINS=", domains);
c0c743cb 750
c2d6bd61
LP
751 r = fflush_and_check(f);
752 if (r < 0)
753 goto fail;
bbf7c048 754
c2d6bd61 755 if (rename(temp_path, m->state_file) < 0) {
bbf7c048 756 r = -errno;
c2d6bd61 757 goto fail;
bbf7c048
TG
758 }
759
e331e246
TG
760 if (m->operational_state != operstate) {
761 m->operational_state = operstate;
762 r = manager_send_changed(m, "OperationalState", NULL);
763 if (r < 0)
764 log_error_errno(r, "Could not emit changed OperationalState: %m");
765 }
766
c2d6bd61 767 return 0;
bbf7c048 768
c2d6bd61 769fail:
da927ba9 770 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
c2d6bd61
LP
771 unlink(m->state_file);
772 unlink(temp_path);
bbf7c048
TG
773 return r;
774}
11bf3cce 775
0dd25fb9 776int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce
LP
777 AddressPool *p;
778 int r;
779
780 assert(m);
781 assert(prefixlen > 0);
782 assert(found);
783
784 LIST_FOREACH(address_pools, p, m->address_pools) {
785 if (p->family != family)
786 continue;
787
788 r = address_pool_acquire(p, prefixlen, found);
789 if (r != 0)
790 return r;
791 }
792
793 return 0;
794}
cb9fc36a
LP
795
796const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
797 if (b == ADDRESS_FAMILY_YES ||
798 b == ADDRESS_FAMILY_NO)
799 return yes_no(b == ADDRESS_FAMILY_YES);
800
801 if (b == ADDRESS_FAMILY_IPV4)
802 return "ipv4";
803 if (b == ADDRESS_FAMILY_IPV6)
804 return "ipv6";
805
806 return NULL;
807}
808
809AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
810 int r;
811
812 /* Make this a true superset of a boolean */
813
814 r = parse_boolean(s);
815 if (r > 0)
816 return ADDRESS_FAMILY_YES;
817 if (r == 0)
818 return ADDRESS_FAMILY_NO;
819
820 if (streq(s, "ipv4"))
821 return ADDRESS_FAMILY_IPV4;
822 if (streq(s, "ipv6"))
823 return ADDRESS_FAMILY_IPV6;
824
825 return _ADDRESS_FAMILY_BOOLEAN_INVALID;
826}
769d324c
LP
827
828DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");