chiark / gitweb /
sysv-generator: Skip init scripts for existing native services
[elogind.git] / src / network / networkd-manager.c
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
22 #include <sys/socket.h>
23 #include <linux/if.h>
24
25 #include "conf-parser.h"
26 #include "path-util.h"
27 #include "networkd.h"
28 #include "networkd-netdev.h"
29 #include "networkd-link.h"
30 #include "network-internal.h"
31 #include "libudev-private.h"
32 #include "udev-util.h"
33 #include "rtnl-util.h"
34 #include "bus-util.h"
35 #include "def.h"
36 #include "mkdir.h"
37 #include "virt.h"
38
39 #include "sd-rtnl.h"
40 #include "sd-daemon.h"
41
42 /* use 8 MB for receive socket kernel queue. */
43 #define RCVBUF_SIZE    (8*1024*1024)
44
45 const char* const network_dirs[] = {
46         "/etc/systemd/network",
47         "/run/systemd/network",
48         "/usr/lib/systemd/network",
49 #ifdef HAVE_SPLIT_USR
50         "/lib/systemd/network",
51 #endif
52         NULL};
53
54 static 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
81 static 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
94 static 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
110 static 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
133 int 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_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
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_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
178         if (r < 0)
179                return log_error_errno(r, "Failed to add network object vtable: %m");
180
181         r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
182         if (r < 0)
183                 return log_error_errno(r, "Failed to add network enumerator: %m");
184
185         r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
186         if (r < 0)
187                 return log_error_errno(r, "Failed to register name: %m");
188
189         r = sd_bus_attach_event(m->bus, m->event, 0);
190         if (r < 0)
191                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
192
193         return 0;
194 }
195
196 static int manager_udev_process_link(Manager *m, struct udev_device *device) {
197         Link *link = NULL;
198         int r, ifindex;
199
200         assert(m);
201         assert(device);
202
203         if (!streq_ptr(udev_device_get_action(device), "add"))
204                 return 0;
205
206         ifindex = udev_device_get_ifindex(device);
207         if (ifindex <= 0) {
208                 log_debug("ignoring udev ADD event for device with invalid ifindex");
209                 return 0;
210         }
211
212         r = link_get(m, ifindex, &link);
213         if (r == -ENODEV)
214                 return 0;
215         else if (r < 0)
216                 return r;
217
218         r = link_initialized(link, device);
219         if (r < 0)
220                 return r;
221
222         return 0;
223 }
224
225 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
226         Manager *m = userdata;
227         struct udev_monitor *monitor = m->udev_monitor;
228         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
229
230         device = udev_monitor_receive_device(monitor);
231         if (!device)
232                 return -ENOMEM;
233
234         manager_udev_process_link(m, device);
235         return 0;
236 }
237
238 static int manager_connect_udev(Manager *m) {
239         int r;
240
241         /* udev does not initialize devices inside containers,
242          * so we rely on them being already initialized before
243          * entering the container */
244         if (detect_container(NULL) > 0)
245                 return 0;
246
247         m->udev = udev_new();
248         if (!m->udev)
249                 return -ENOMEM;
250
251         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
252         if (!m->udev_monitor)
253                 return -ENOMEM;
254
255         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
256         if (r < 0)
257                 return log_error_errno(r, "Could not add udev monitor filter: %m");
258
259         r = udev_monitor_enable_receiving(m->udev_monitor);
260         if (r < 0) {
261                 log_error("Could not enable udev monitor");
262                 return r;
263         }
264
265         r = sd_event_add_io(m->event,
266                         &m->udev_event_source,
267                         udev_monitor_get_fd(m->udev_monitor),
268                         EPOLLIN, manager_dispatch_link_udev,
269                         m);
270         if (r < 0)
271                 return r;
272
273         r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
274         if (r < 0)
275                 return r;
276
277         return 0;
278 }
279
280 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
281         Manager *m = userdata;
282         Link *link = NULL;
283         NetDev *netdev = NULL;
284         uint16_t type;
285         const char *name;
286         int r, ifindex;
287
288         assert(rtnl);
289         assert(message);
290         assert(m);
291
292         if (sd_rtnl_message_is_error(message)) {
293                 r = sd_rtnl_message_get_errno(message);
294                 if (r < 0)
295                         log_warning_errno(r, "rtnl: could not receive link: %m");
296
297                 return 0;
298         }
299
300         r = sd_rtnl_message_get_type(message, &type);
301         if (r < 0) {
302                 log_warning_errno(r, "rtnl: could not get message type: %m");
303                 return 0;
304         }
305
306         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
307         if (r < 0) {
308                 log_warning_errno(r, "rtnl: could not get ifindex: %m");
309                 return 0;
310         } else if (ifindex <= 0) {
311                 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
312                 return 0;
313         } else
314                 link_get(m, ifindex, &link);
315
316         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
317         if (r < 0) {
318                 log_warning_errno(r, "rtnl: received link message without ifname: %m");
319                 return 0;
320         } else
321                 netdev_get(m, name, &netdev);
322
323         switch (type) {
324         case RTM_NEWLINK:
325                 if (!link) {
326                         /* link is new, so add it */
327                         r = link_add(m, message, &link);
328                         if (r < 0) {
329                                 log_warning_errno(r, "could not add new link: %m");
330                                 return 0;
331                         }
332                 }
333
334                 if (netdev) {
335                         /* netdev exists, so make sure the ifindex matches */
336                         r = netdev_set_ifindex(netdev, message);
337                         if (r < 0) {
338                                 log_warning_errno(r, "could not set ifindex on netdev: %m");
339                                 return 0;
340                         }
341                 }
342
343                 r = link_update(link, message);
344                 if (r < 0)
345                         return 0;
346
347                 break;
348
349         case RTM_DELLINK:
350                 link_drop(link);
351                 netdev_drop(netdev);
352
353                 break;
354
355         default:
356                 assert_not_reached("Received invalid RTNL message type.");
357         }
358
359         return 1;
360 }
361
362 static int systemd_netlink_fd(void) {
363         int n, fd, rtnl_fd = -EINVAL;
364
365         n = sd_listen_fds(true);
366         if (n <= 0)
367                 return -EINVAL;
368
369         for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd ++) {
370                 if (sd_is_socket(fd, AF_NETLINK, SOCK_RAW, -1) > 0) {
371                         if (rtnl_fd >= 0)
372                                 return -EINVAL;
373
374                         rtnl_fd = fd;
375                 }
376         }
377
378         return rtnl_fd;
379 }
380
381 static int manager_connect_rtnl(Manager *m) {
382         int fd, r;
383
384         assert(m);
385
386         fd = systemd_netlink_fd();
387         if (fd < 0)
388                 r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR, RTNLGRP_IPV6_IFADDR);
389         else
390                 r = sd_rtnl_open_fd(&m->rtnl, fd, 0);
391         if (r < 0)
392                 return r;
393
394         r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
395         if (r < 0)
396                 return r;
397
398         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
399         if (r < 0)
400                 return r;
401
402         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
403         if (r < 0)
404                 return r;
405
406         r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
407         if (r < 0)
408                 return r;
409
410         r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
411         if (r < 0)
412                 return r;
413
414         r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
415         if (r < 0)
416                 return r;
417
418         return 0;
419 }
420
421 int manager_new(Manager **ret) {
422         _cleanup_manager_free_ Manager *m = NULL;
423         int r;
424
425         m = new0(Manager, 1);
426         if (!m)
427                 return -ENOMEM;
428
429         m->state_file = strdup("/run/systemd/netif/state");
430         if (!m->state_file)
431                 return -ENOMEM;
432
433         r = sd_event_default(&m->event);
434         if (r < 0)
435                 return r;
436
437         sd_event_set_watchdog(m->event, true);
438
439         sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
440         sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
441
442         r = manager_connect_rtnl(m);
443         if (r < 0)
444                 return r;
445
446         r = manager_connect_udev(m);
447         if (r < 0)
448                 return r;
449
450         m->netdevs = hashmap_new(&string_hash_ops);
451         if (!m->netdevs)
452                 return -ENOMEM;
453
454         LIST_HEAD_INIT(m->networks);
455
456         r = setup_default_address_pool(m);
457         if (r < 0)
458                 return r;
459
460         *ret = m;
461         m = NULL;
462
463         return 0;
464 }
465
466 void manager_free(Manager *m) {
467         Network *network;
468         NetDev *netdev;
469         Link *link;
470         AddressPool *pool;
471
472         if (!m)
473                 return;
474
475         free(m->state_file);
476
477         udev_monitor_unref(m->udev_monitor);
478         udev_unref(m->udev);
479         sd_bus_unref(m->bus);
480         sd_bus_slot_unref(m->prepare_for_sleep_slot);
481         sd_event_source_unref(m->udev_event_source);
482         sd_event_source_unref(m->bus_retry_event_source);
483         sd_event_unref(m->event);
484
485         while ((link = hashmap_first(m->links)))
486                 link_unref(link);
487         hashmap_free(m->links);
488
489         while ((network = m->networks))
490                 network_free(network);
491
492         hashmap_free(m->networks_by_name);
493
494         while ((netdev = hashmap_first(m->netdevs)))
495                 netdev_unref(netdev);
496         hashmap_free(m->netdevs);
497
498         while ((pool = m->address_pools))
499                 address_pool_free(pool);
500
501         sd_rtnl_unref(m->rtnl);
502
503         free(m);
504 }
505
506 static bool manager_check_idle(void *userdata) {
507         Manager *m = userdata;
508         Link *link;
509         Iterator i;
510
511         assert(m);
512
513         HASHMAP_FOREACH(link, m->links, i) {
514                 /* we are not woken on udev activity, so let's just wait for the
515                  * pending udev event */
516                 if (link->state == LINK_STATE_PENDING)
517                         return false;
518
519                 if (!link->network)
520                         continue;
521
522                 /* we are not woken on netork activity, so let's stay around */
523                 if (link_lldp_enabled(link) ||
524                     link_ipv4ll_enabled(link) ||
525                     link_dhcp4_server_enabled(link) ||
526                     link_dhcp4_enabled(link) ||
527                     link_dhcp6_enabled(link))
528                         return false;
529         }
530
531         return true;
532 }
533
534 int manager_run(Manager *m) {
535         assert(m);
536
537         return bus_event_loop_with_idle(
538                         m->event,
539                         m->bus,
540                         "org.freedesktop.network1",
541                         DEFAULT_EXIT_USEC,
542                         manager_check_idle,
543                         m);
544 }
545
546 int manager_load_config(Manager *m) {
547         int r;
548
549         /* update timestamp */
550         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
551
552         r = netdev_load(m);
553         if (r < 0)
554                 return r;
555
556         r = network_load(m);
557         if (r < 0)
558                 return r;
559
560         return 0;
561 }
562
563 bool manager_should_reload(Manager *m) {
564         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
565 }
566
567 int manager_rtnl_enumerate_links(Manager *m) {
568         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
569         sd_rtnl_message *link;
570         int r;
571
572         assert(m);
573         assert(m->rtnl);
574
575         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
576         if (r < 0)
577                 return r;
578
579         r = sd_rtnl_message_request_dump(req, true);
580         if (r < 0)
581                 return r;
582
583         r = sd_rtnl_call(m->rtnl, req, 0, &reply);
584         if (r < 0)
585                 return r;
586
587         for (link = reply; link; link = sd_rtnl_message_next(link)) {
588                 int k;
589
590                 m->enumerating = true;
591
592                 k = manager_rtnl_process_link(m->rtnl, link, m);
593                 if (k < 0)
594                         r = k;
595
596                 m->enumerating = false;
597         }
598
599         return r;
600 }
601
602 int manager_rtnl_enumerate_addresses(Manager *m) {
603         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
604         sd_rtnl_message *addr;
605         int r;
606
607         assert(m);
608         assert(m->rtnl);
609
610         r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
611         if (r < 0)
612                 return r;
613
614         r = sd_rtnl_message_request_dump(req, true);
615         if (r < 0)
616                 return r;
617
618         r = sd_rtnl_call(m->rtnl, req, 0, &reply);
619         if (r < 0)
620                 return r;
621
622         for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
623                 int k;
624
625                 m->enumerating = true;
626
627                 k = link_rtnl_process_address(m->rtnl, addr, m);
628                 if (k < 0)
629                         r = k;
630
631                 m->enumerating = false;
632         }
633
634         return r;
635 }
636
637 static int set_put_in_addr(Set *s, const struct in_addr *address) {
638         char *p;
639         int r;
640
641         assert(s);
642
643         r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
644         if (r < 0)
645                 return r;
646
647         r = set_consume(s, p);
648         if (r == -EEXIST)
649                 return 0;
650
651         return r;
652 }
653
654 static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
655         int r, i, c = 0;
656
657         assert(s);
658         assert(n <= 0 || addresses);
659
660         for (i = 0; i < n; i++) {
661                 r = set_put_in_addr(s, addresses+i);
662                 if (r < 0)
663                         return r;
664
665                 c += r;
666         }
667
668         return c;
669 }
670
671 static void print_string_set(FILE *f, const char *field, Set *s) {
672         bool space = false;
673         Iterator i;
674         char *p;
675
676         if (set_isempty(s))
677                 return;
678
679         fputs(field, f);
680
681         SET_FOREACH(p, s, i) {
682                 if (space)
683                         fputc(' ', f);
684                 fputs(p, f);
685                 space = true;
686         }
687         fputc('\n', f);
688 }
689
690 int manager_save(Manager *m) {
691         _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
692         Link *link;
693         Iterator i;
694         _cleanup_free_ char *temp_path = NULL;
695         _cleanup_fclose_ FILE *f = NULL;
696         LinkOperationalState operstate = LINK_OPERSTATE_OFF;
697         const char *operstate_str;
698         int r;
699
700         assert(m);
701         assert(m->state_file);
702
703         /* We add all NTP and DNS server to a set, to filter out duplicates */
704         dns = set_new(&string_hash_ops);
705         if (!dns)
706                 return -ENOMEM;
707
708         ntp = set_new(&string_hash_ops);
709         if (!ntp)
710                 return -ENOMEM;
711
712         domains = set_new(&string_hash_ops);
713         if (!domains)
714                 return -ENOMEM;
715
716         HASHMAP_FOREACH(link, m->links, i) {
717                 if (link->flags & IFF_LOOPBACK)
718                         continue;
719
720                 if (link->operstate > operstate)
721                         operstate = link->operstate;
722
723                 if (!link->network)
724                         continue;
725
726                 /* First add the static configured entries */
727                 r = set_put_strdupv(dns, link->network->dns);
728                 if (r < 0)
729                         return r;
730
731                 r = set_put_strdupv(ntp, link->network->ntp);
732                 if (r < 0)
733                         return r;
734
735                 r = set_put_strdupv(domains, link->network->domains);
736                 if (r < 0)
737                         return r;
738
739                 if (!link->dhcp_lease)
740                         continue;
741
742                 /* Secondly, add the entries acquired via DHCP */
743                 if (link->network->dhcp_dns) {
744                         const struct in_addr *addresses;
745
746                         r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
747                         if (r > 0) {
748                                 r = set_put_in_addrv(dns, addresses, r);
749                                 if (r < 0)
750                                         return r;
751                         } else if (r < 0 && r != -ENOENT)
752                                 return r;
753                 }
754
755                 if (link->network->dhcp_ntp) {
756                         const struct in_addr *addresses;
757
758                         r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
759                         if (r > 0) {
760                                 r = set_put_in_addrv(ntp, addresses, r);
761                                 if (r < 0)
762                                         return r;
763                         } else if (r < 0 && r != -ENOENT)
764                                 return r;
765                 }
766
767                 if (link->network->dhcp_domains) {
768                         const char *domainname;
769
770                         r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
771                         if (r >= 0) {
772                                 r = set_put_strdup(domains, domainname);
773                                 if (r < 0)
774                                         return r;
775                         } else if (r != -ENOENT)
776                                 return r;
777                 }
778         }
779
780         operstate_str = link_operstate_to_string(operstate);
781         assert(operstate_str);
782
783         r = fopen_temporary(m->state_file, &f, &temp_path);
784         if (r < 0)
785                 return r;
786
787         fchmod(fileno(f), 0644);
788
789         fprintf(f,
790                 "# This is private data. Do not parse.\n"
791                 "OPER_STATE=%s\n", operstate_str);
792
793         print_string_set(f, "DNS=", dns);
794         print_string_set(f, "NTP=", ntp);
795         print_string_set(f, "DOMAINS=", domains);
796
797         r = fflush_and_check(f);
798         if (r < 0)
799                 goto fail;
800
801         if (rename(temp_path, m->state_file) < 0) {
802                 r = -errno;
803                 goto fail;
804         }
805
806         if (m->operational_state != operstate) {
807                 m->operational_state = operstate;
808                 r = manager_send_changed(m, "OperationalState", NULL);
809                 if (r < 0)
810                         log_error_errno(r, "Could not emit changed OperationalState: %m");
811         }
812
813         return 0;
814
815 fail:
816         log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
817         unlink(m->state_file);
818         unlink(temp_path);
819         return r;
820 }
821
822 int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
823         AddressPool *p;
824         int r;
825
826         assert(m);
827         assert(prefixlen > 0);
828         assert(found);
829
830         LIST_FOREACH(address_pools, p, m->address_pools) {
831                 if (p->family != family)
832                         continue;
833
834                 r = address_pool_acquire(p, prefixlen, found);
835                 if (r != 0)
836                         return r;
837         }
838
839         return 0;
840 }
841
842 const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
843         if (b == ADDRESS_FAMILY_YES ||
844             b == ADDRESS_FAMILY_NO)
845                 return yes_no(b == ADDRESS_FAMILY_YES);
846
847         if (b == ADDRESS_FAMILY_IPV4)
848                 return "ipv4";
849         if (b == ADDRESS_FAMILY_IPV6)
850                 return "ipv6";
851
852         return NULL;
853 }
854
855 AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
856         int r;
857
858         /* Make this a true superset of a boolean */
859
860         r = parse_boolean(s);
861         if (r > 0)
862                 return ADDRESS_FAMILY_YES;
863         if (r == 0)
864                 return ADDRESS_FAMILY_NO;
865
866         if (streq(s, "ipv4"))
867                 return ADDRESS_FAMILY_IPV4;
868         if (streq(s, "ipv6"))
869                 return ADDRESS_FAMILY_IPV6;
870
871         return _ADDRESS_FAMILY_BOOLEAN_INVALID;
872 }
873
874 DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");