]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
sd-rtnl: allow sd_rtnl_open_fd() to be used on bound sockets
[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
154 r = sd_bus_attach_event(m->bus, m->event, 0);
155 if (r < 0)
156 return r;
157
158 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
159 "type='signal',"
160 "sender='org.freedesktop.login1',"
161 "interface='org.freedesktop.login1.Manager',"
162 "member='PrepareForSleep',"
163 "path='/org/freedesktop/login1'",
164 match_prepare_for_sleep,
165 m);
166 if (r < 0)
167 return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
168
169 return 0;
170}
171
44de0efc
LP
172static int systemd_netlink_fd(void) {
173 int n, fd, rtnl_fd = -EINVAL;
5544ee85
TG
174
175 n = sd_listen_fds(true);
176 if (n <= 0)
177 return -EINVAL;
178
179 for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
180 if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
181 if (rtnl_fd >= 0)
182 return -EINVAL;
183
184 rtnl_fd = fd;
185 }
186 }
187
44de0efc 188 return rtnl_fd;
5544ee85
TG
189}
190
f579559b
TG
191int manager_new(Manager **ret) {
192 _cleanup_manager_free_ Manager *m = NULL;
5544ee85 193 int r, fd;
f579559b
TG
194
195 m = new0(Manager, 1);
196 if (!m)
197 return -ENOMEM;
198
85b5673b 199 m->state_file = strdup("/run/systemd/netif/state");
bbf7c048
TG
200 if (!m->state_file)
201 return -ENOMEM;
202
afc6adb5 203 r = sd_event_default(&m->event);
f579559b
TG
204 if (r < 0)
205 return r;
206
cde93897
LP
207 sd_event_set_watchdog(m->event, true);
208
186fe1db
LP
209 sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
210 sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
211
44de0efc
LP
212 fd = systemd_netlink_fd();
213 if (fd < 0)
214 r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
215 else
5544ee85 216 r = sd_rtnl_new_from_netlink(&m->rtnl, fd);
44de0efc
LP
217 if (r < 0)
218 return r;
219
9c0a72f9 220 r = manager_connect_bus(m);
44de0efc
LP
221 if (r < 0)
222 return r;
be660c37 223
60ad0c85
TG
224 /* udev does not initialize devices inside containers,
225 * so we rely on them being already initialized before
226 * entering the container */
505f8da7
TG
227 if (detect_container(NULL) <= 0) {
228 m->udev = udev_new();
229 if (!m->udev)
60ad0c85 230 return -ENOMEM;
505f8da7 231
60ad0c85
TG
232 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
233 if (!m->udev_monitor)
234 return -ENOMEM;
235 }
f579559b 236
d5099efc 237 m->netdevs = hashmap_new(&string_hash_ops);
52433f6b 238 if (!m->netdevs)
02b59d57
TG
239 return -ENOMEM;
240
f579559b
TG
241 LIST_HEAD_INIT(m->networks);
242
11bf3cce
LP
243 r = setup_default_address_pool(m);
244 if (r < 0)
245 return r;
246
f579559b
TG
247 *ret = m;
248 m = NULL;
249
250 return 0;
251}
252
253void manager_free(Manager *m) {
0617ffab 254 Network *network;
1a436809 255 NetDev *netdev;
0617ffab 256 Link *link;
11bf3cce 257 AddressPool *pool;
0617ffab 258
624b5a63
TG
259 if (!m)
260 return;
261
bbf7c048
TG
262 free(m->state_file);
263
f579559b
TG
264 udev_monitor_unref(m->udev_monitor);
265 udev_unref(m->udev);
1346b1f0 266 sd_bus_unref(m->bus);
9c0a72f9 267 sd_bus_slot_unref(m->prepare_for_sleep_slot);
f579559b 268 sd_event_source_unref(m->udev_event_source);
9c0a72f9 269 sd_event_source_unref(m->bus_retry_event_source);
f579559b 270 sd_event_unref(m->event);
0617ffab 271
0617ffab 272 while ((link = hashmap_first(m->links)))
14b746f7 273 link_unref(link);
f579559b 274 hashmap_free(m->links);
0617ffab 275
2292547a
TG
276 while ((network = m->networks))
277 network_free(network);
278
52433f6b 279 while ((netdev = hashmap_first(m->netdevs)))
14b746f7 280 netdev_unref(netdev);
52433f6b 281 hashmap_free(m->netdevs);
02b59d57 282
11bf3cce
LP
283 while ((pool = m->address_pools))
284 address_pool_free(pool);
285
f579559b
TG
286 sd_rtnl_unref(m->rtnl);
287
288 free(m);
289}
290
02b59d57
TG
291int manager_load_config(Manager *m) {
292 int r;
293
294 /* update timestamp */
2ad8416d 295 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
02b59d57 296
52433f6b 297 r = netdev_load(m);
02b59d57
TG
298 if (r < 0)
299 return r;
300
301 r = network_load(m);
302 if (r < 0)
303 return r;
304
305 return 0;
306}
307
308bool manager_should_reload(Manager *m) {
2ad8416d 309 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
02b59d57
TG
310}
311
505f8da7 312static int manager_udev_process_link(Manager *m, struct udev_device *device) {
11a7f229 313 Link *link = NULL;
667fcc6d 314 int r, ifindex;
f579559b 315
11a7f229
TG
316 assert(m);
317 assert(device);
f579559b 318
505f8da7
TG
319 if (!streq_ptr(udev_device_get_action(device), "add"))
320 return 0;
321
667fcc6d
TG
322 ifindex = udev_device_get_ifindex(device);
323 if (ifindex <= 0) {
324 log_debug("ignoring udev ADD event for device with invalid ifindex");
325 return 0;
326 }
505f8da7 327
667fcc6d
TG
328 r = link_get(m, ifindex, &link);
329 if (r == -ENODEV)
505f8da7 330 return 0;
667fcc6d
TG
331 else if (r < 0)
332 return r;
505f8da7
TG
333
334 r = link_initialized(link, device);
335 if (r < 0)
336 return r;
11a7f229 337
505f8da7
TG
338 return 0;
339}
f579559b 340
505f8da7
TG
341static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
342 Manager *m = userdata;
343 Link *link = NULL;
4d473d5d 344 NetDev *netdev = NULL;
f2236469 345 uint16_t type;
ca4e095a 346 const char *name;
505f8da7 347 int r, ifindex;
f579559b 348
505f8da7
TG
349 assert(rtnl);
350 assert(message);
f579559b
TG
351 assert(m);
352
45af44d4
TG
353 if (sd_rtnl_message_is_error(message)) {
354 r = sd_rtnl_message_get_errno(message);
355 if (r < 0)
356 log_warning_errno(r, "rtnl: could not receive link: %m");
357
358 return 0;
359 }
360
f2236469
TG
361 r = sd_rtnl_message_get_type(message, &type);
362 if (r < 0) {
45af44d4 363 log_warning_errno(r, "rtnl: could not get message type: %m");
f2236469
TG
364 return 0;
365 }
366
505f8da7 367 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
45af44d4
TG
368 if (r < 0) {
369 log_warning_errno(r, "rtnl: could not get ifindex: %m");
370 return 0;
371 } else if (ifindex <= 0) {
372 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
505f8da7 373 return 0;
4d473d5d
TG
374 } else
375 link_get(m, ifindex, &link);
f579559b 376
505f8da7 377 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
45af44d4
TG
378 if (r < 0) {
379 log_warning_errno(r, "rtnl: received link message without ifname: %m");
4d473d5d
TG
380 return 0;
381 } else
f2236469 382 netdev_get(m, name, &netdev);
4d473d5d
TG
383
384 switch (type) {
385 case RTM_NEWLINK:
386 if (!link) {
387 /* link is new, so add it */
388 r = link_add(m, message, &link);
389 if (r < 0) {
17d1f37d 390 log_warning_errno(r, "could not add new link: %m");
4d473d5d
TG
391 return 0;
392 }
393 }
394
395 if (netdev) {
396 /* netdev exists, so make sure the ifindex matches */
505f8da7
TG
397 r = netdev_set_ifindex(netdev, message);
398 if (r < 0) {
17d1f37d 399 log_warning_errno(r, "could not set ifindex on netdev: %m");
505f8da7
TG
400 return 0;
401 }
402 }
e1202047 403
f2236469
TG
404 r = link_update(link, message);
405 if (r < 0)
406 return 0;
4d473d5d
TG
407
408 break;
409
410 case RTM_DELLINK:
411 link_drop(link);
412 netdev_drop(netdev);
413
414 break;
415
416 default:
417 assert_not_reached("Received invalid RTNL message type.");
f2236469 418 }
505f8da7
TG
419
420 return 1;
421}
422
423int manager_rtnl_enumerate_links(Manager *m) {
424 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
425 sd_rtnl_message *link;
45af44d4 426 int r;
505f8da7
TG
427
428 assert(m);
429 assert(m->rtnl);
430
431 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
432 if (r < 0)
433 return r;
434
435 r = sd_rtnl_message_request_dump(req, true);
f579559b 436 if (r < 0)
bf5332d2 437 return r;
f579559b 438
505f8da7
TG
439 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
440 if (r < 0)
441 return r;
f579559b 442
505f8da7 443 for (link = reply; link; link = sd_rtnl_message_next(link)) {
45af44d4 444 int k;
505f8da7 445
45af44d4 446 k = manager_rtnl_process_link(m->rtnl, link, m);
505f8da7 447 if (k < 0)
45af44d4
TG
448 r = k;
449 }
450
451 return r;
452}
505f8da7 453
45af44d4
TG
454int manager_rtnl_enumerate_addresses(Manager *m) {
455 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
456 sd_rtnl_message *addr;
457 int r;
f579559b 458
45af44d4
TG
459 assert(m);
460 assert(m->rtnl);
461
462 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
463 if (r < 0)
464 return r;
465
466 r = sd_rtnl_message_request_dump(req, true);
467 if (r < 0)
468 return r;
469
470 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
471 if (r < 0)
472 return r;
473
474 for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
475 int k;
476
477 k = link_rtnl_process_address(m->rtnl, addr, m);
f579559b
TG
478 if (k < 0)
479 r = k;
480 }
481
f579559b
TG
482 return r;
483}
484
485static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
486 Manager *m = userdata;
487 struct udev_monitor *monitor = m->udev_monitor;
7b77ed8c 488 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
f579559b
TG
489
490 device = udev_monitor_receive_device(monitor);
491 if (!device)
492 return -ENOMEM;
493
505f8da7 494 manager_udev_process_link(m, device);
f579559b
TG
495 return 0;
496}
497
498int manager_udev_listen(Manager *m) {
499 int r;
500
505f8da7
TG
501 if (detect_container(NULL) > 0)
502 return 0;
503
504 assert(m->udev_monitor);
505
f579559b 506 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
f647962d
MS
507 if (r < 0)
508 return log_error_errno(r, "Could not add udev monitor filter: %m");
f579559b 509
f579559b
TG
510 r = udev_monitor_enable_receiving(m->udev_monitor);
511 if (r < 0) {
512 log_error("Could not enable udev monitor");
513 return r;
514 }
515
516 r = sd_event_add_io(m->event,
151b9b96 517 &m->udev_event_source,
f579559b
TG
518 udev_monitor_get_fd(m->udev_monitor),
519 EPOLLIN, manager_dispatch_link_udev,
151b9b96 520 m);
f579559b
TG
521 if (r < 0)
522 return r;
523
356779df 524 r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
9021bb9f
TG
525 if (r < 0)
526 return r;
527
f579559b
TG
528 return 0;
529}
f882c247
TG
530
531int manager_rtnl_listen(Manager *m) {
532 int r;
533
5da8149f
TG
534 assert(m);
535
f882c247
TG
536 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
537 if (r < 0)
538 return r;
539
dd3efc09
TG
540 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
541 if (r < 0)
542 return r;
543
f2236469
TG
544 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
545 if (r < 0)
546 return r;
547
fbbeb65a 548 r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
2e9f08ea
TG
549 if (r < 0)
550 return r;
551
fbbeb65a 552 r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
2e9f08ea
TG
553 if (r < 0)
554 return r;
555
f882c247
TG
556 return 0;
557}
3bef724f 558
1346b1f0
TG
559int manager_bus_listen(Manager *m) {
560 int r;
561
bcbca829
TG
562 assert(m->event);
563
564 if (!m->bus) /* TODO: drop when we can rely on kdbus */
565 return 0;
566
1346b1f0
TG
567 r = sd_bus_attach_event(m->bus, m->event, 0);
568 if (r < 0)
569 return r;
570
571 return 0;
572}
573
c0c743cb
LP
574static int set_put_in_addr(Set *s, const struct in_addr *address) {
575 char *p;
576 int r;
577
578 assert(s);
579
580 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
581 if (r < 0)
582 return r;
583
584 r = set_consume(s, p);
585 if (r == -EEXIST)
586 return 0;
587
588 return r;
589}
590
591static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
592 int r, i, c = 0;
593
594 assert(s);
595 assert(n <= 0 || addresses);
596
597 for (i = 0; i < n; i++) {
598 r = set_put_in_addr(s, addresses+i);
599 if (r < 0)
600 return r;
601
602 c += r;
603 }
604
605 return c;
606}
607
8612e936
LP
608static void print_string_set(FILE *f, const char *field, Set *s) {
609 bool space = false;
610 Iterator i;
611 char *p;
612
613 if (set_isempty(s))
614 return;
615
616 fputs(field, f);
617
618 SET_FOREACH(p, s, i) {
619 if (space)
620 fputc(' ', f);
621 fputs(p, f);
622 space = true;
623 }
624 fputc('\n', f);
625}
626
bbf7c048 627int manager_save(Manager *m) {
8612e936 628 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
bbf7c048
TG
629 Link *link;
630 Iterator i;
631 _cleanup_free_ char *temp_path = NULL;
632 _cleanup_fclose_ FILE *f = NULL;
d3df0e39 633 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
e375dcde 634 const char *operstate_str;
bbf7c048
TG
635 int r;
636
637 assert(m);
638 assert(m->state_file);
639
c0c743cb 640 /* We add all NTP and DNS server to a set, to filter out duplicates */
d5099efc 641 dns = set_new(&string_hash_ops);
c0c743cb
LP
642 if (!dns)
643 return -ENOMEM;
644
d5099efc 645 ntp = set_new(&string_hash_ops);
c0c743cb
LP
646 if (!ntp)
647 return -ENOMEM;
648
d5099efc 649 domains = set_new(&string_hash_ops);
8612e936
LP
650 if (!domains)
651 return -ENOMEM;
652
bbf7c048
TG
653 HASHMAP_FOREACH(link, m->links, i) {
654 if (link->flags & IFF_LOOPBACK)
655 continue;
656
e375dcde
TG
657 if (link->operstate > operstate)
658 operstate = link->operstate;
c0c743cb
LP
659
660 if (!link->network)
661 continue;
662
663 /* First add the static configured entries */
664 r = set_put_strdupv(dns, link->network->dns);
665 if (r < 0)
666 return r;
667
668 r = set_put_strdupv(ntp, link->network->ntp);
669 if (r < 0)
670 return r;
671
8612e936
LP
672 r = set_put_strdupv(domains, link->network->domains);
673 if (r < 0)
674 return r;
675
c0c743cb
LP
676 if (!link->dhcp_lease)
677 continue;
678
679 /* Secondly, add the entries acquired via DHCP */
680 if (link->network->dhcp_dns) {
681 const struct in_addr *addresses;
682
683 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
684 if (r > 0) {
685 r = set_put_in_addrv(dns, addresses, r);
686 if (r < 0)
687 return r;
8612e936 688 } else if (r < 0 && r != -ENOENT)
c0c743cb
LP
689 return r;
690 }
691
692 if (link->network->dhcp_ntp) {
693 const struct in_addr *addresses;
694
695 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
696 if (r > 0) {
697 r = set_put_in_addrv(ntp, addresses, r);
698 if (r < 0)
699 return r;
8612e936
LP
700 } else if (r < 0 && r != -ENOENT)
701 return r;
702 }
703
704 if (link->network->dhcp_domains) {
705 const char *domainname;
706
707 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
708 if (r >= 0) {
709 r = set_put_strdup(domains, domainname);
710 if (r < 0)
711 return r;
c0c743cb
LP
712 } else if (r != -ENOENT)
713 return r;
714 }
bbf7c048
TG
715 }
716
e375dcde
TG
717 operstate_str = link_operstate_to_string(operstate);
718 assert(operstate_str);
bbf7c048
TG
719
720 r = fopen_temporary(m->state_file, &f, &temp_path);
721 if (r < 0)
c2d6bd61 722 return r;
bbf7c048
TG
723
724 fchmod(fileno(f), 0644);
725
726 fprintf(f,
727 "# This is private data. Do not parse.\n"
e375dcde 728 "OPER_STATE=%s\n", operstate_str);
bbf7c048 729
8612e936
LP
730 print_string_set(f, "DNS=", dns);
731 print_string_set(f, "NTP=", ntp);
732 print_string_set(f, "DOMAINS=", domains);
c0c743cb 733
c2d6bd61
LP
734 r = fflush_and_check(f);
735 if (r < 0)
736 goto fail;
bbf7c048 737
c2d6bd61 738 if (rename(temp_path, m->state_file) < 0) {
bbf7c048 739 r = -errno;
c2d6bd61 740 goto fail;
bbf7c048
TG
741 }
742
c2d6bd61 743 return 0;
bbf7c048 744
c2d6bd61 745fail:
da927ba9 746 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
c2d6bd61
LP
747 unlink(m->state_file);
748 unlink(temp_path);
bbf7c048
TG
749 return r;
750}
11bf3cce 751
0dd25fb9 752int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce
LP
753 AddressPool *p;
754 int r;
755
756 assert(m);
757 assert(prefixlen > 0);
758 assert(found);
759
760 LIST_FOREACH(address_pools, p, m->address_pools) {
761 if (p->family != family)
762 continue;
763
764 r = address_pool_acquire(p, prefixlen, found);
765 if (r != 0)
766 return r;
767 }
768
769 return 0;
770}
cb9fc36a
LP
771
772const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
773 if (b == ADDRESS_FAMILY_YES ||
774 b == ADDRESS_FAMILY_NO)
775 return yes_no(b == ADDRESS_FAMILY_YES);
776
777 if (b == ADDRESS_FAMILY_IPV4)
778 return "ipv4";
779 if (b == ADDRESS_FAMILY_IPV6)
780 return "ipv6";
781
782 return NULL;
783}
784
785AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
786 int r;
787
788 /* Make this a true superset of a boolean */
789
790 r = parse_boolean(s);
791 if (r > 0)
792 return ADDRESS_FAMILY_YES;
793 if (r == 0)
794 return ADDRESS_FAMILY_NO;
795
796 if (streq(s, "ipv4"))
797 return ADDRESS_FAMILY_IPV4;
798 if (streq(s, "ipv6"))
799 return ADDRESS_FAMILY_IPV6;
800
801 return _ADDRESS_FAMILY_BOOLEAN_INVALID;
802}
769d324c
LP
803
804DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");