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