chiark / gitweb /
40328a36c95de117f0c1a751ba0f3d3b8f23a94e
[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 "mkdir.h"
35 #include "virt.h"
36
37 #include "sd-rtnl.h"
38 #include "sd-daemon.h"
39
40 /* use 8 MB for receive socket kernel queue. */
41 #define RCVBUF_SIZE    (8*1024*1024)
42
43 const char* const network_dirs[] = {
44         "/etc/systemd/network",
45         "/run/systemd/network",
46         "/usr/lib/systemd/network",
47 #ifdef HAVE_SPLIT_USR
48         "/lib/systemd/network",
49 #endif
50         NULL};
51
52 static 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
79 int manager_connect_bus(Manager *m);
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_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
185         return 0;
186 }
187
188 static int manager_udev_process_link(Manager *m, struct udev_device *device) {
189         Link *link = NULL;
190         int r, ifindex;
191
192         assert(m);
193         assert(device);
194
195         if (!streq_ptr(udev_device_get_action(device), "add"))
196                 return 0;
197
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;
202         }
203
204         r = link_get(m, ifindex, &link);
205         if (r == -ENODEV)
206                 return 0;
207         else if (r < 0)
208                 return r;
209
210         r = link_initialized(link, device);
211         if (r < 0)
212                 return r;
213
214         return 0;
215 }
216
217 static 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;
221
222         device = udev_monitor_receive_device(monitor);
223         if (!device)
224                 return -ENOMEM;
225
226         manager_udev_process_link(m, device);
227         return 0;
228 }
229
230 static int manager_connect_udev(Manager *m) {
231         int r;
232
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;
238
239         m->udev = udev_new();
240         if (!m->udev)
241                 return -ENOMEM;
242
243         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
244         if (!m->udev_monitor)
245                 return -ENOMEM;
246
247         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
248         if (r < 0)
249                 return log_error_errno(r, "Could not add udev monitor filter: %m");
250
251         r = udev_monitor_enable_receiving(m->udev_monitor);
252         if (r < 0) {
253                 log_error("Could not enable udev monitor");
254                 return r;
255         }
256
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)
263                 return r;
264
265         r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
266         if (r < 0)
267                 return r;
268
269         return 0;
270 }
271
272 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
273         Manager *m = userdata;
274         Link *link = NULL;
275         NetDev *netdev = NULL;
276         uint16_t type;
277         const char *name;
278         int r, ifindex;
279
280         assert(rtnl);
281         assert(message);
282         assert(m);
283
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
292         r = sd_rtnl_message_get_type(message, &type);
293         if (r < 0) {
294                 log_warning_errno(r, "rtnl: could not get message type: %m");
295                 return 0;
296         }
297
298         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
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);
304                 return 0;
305         } else
306                 link_get(m, ifindex, &link);
307
308         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
309         if (r < 0) {
310                 log_warning_errno(r, "rtnl: received link message without ifname: %m");
311                 return 0;
312         } else
313                 netdev_get(m, name, &netdev);
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) {
321                                 log_warning_errno(r, "could not add new link: %m");
322                                 return 0;
323                         }
324                 }
325
326                 if (netdev) {
327                         /* netdev exists, so make sure the ifindex matches */
328                         r = netdev_set_ifindex(netdev, message);
329                         if (r < 0) {
330                                 log_warning_errno(r, "could not set ifindex on netdev: %m");
331                                 return 0;
332                         }
333                 }
334
335                 r = link_update(link, message);
336                 if (r < 0)
337                         return 0;
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.");
349         }
350
351         return 1;
352 }
353
354 static 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
373 static int manager_connect_rtnl(Manager *m) {
374         int fd, r;
375
376         assert(m);
377
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);
383         if (r < 0)
384                 return r;
385
386         r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
387         if (r < 0)
388                 return r;
389
390         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
391         if (r < 0)
392                 return r;
393
394         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
395         if (r < 0)
396                 return r;
397
398         r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
399         if (r < 0)
400                 return r;
401
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;
411 }
412
413 int manager_new(Manager **ret) {
414         _cleanup_manager_free_ Manager *m = NULL;
415         int r;
416
417         m = new0(Manager, 1);
418         if (!m)
419                 return -ENOMEM;
420
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);
426         if (r < 0)
427                 return r;
428
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);
435         if (r < 0)
436                 return r;
437
438         r = manager_connect_bus(m);
439         if (r < 0)
440                 return r;
441
442         r = manager_connect_udev(m);
443         if (r < 0)
444                 return r;
445
446         m->netdevs = hashmap_new(&string_hash_ops);
447         if (!m->netdevs)
448                 return -ENOMEM;
449
450         LIST_HEAD_INIT(m->networks);
451
452         r = setup_default_address_pool(m);
453         if (r < 0)
454                 return r;
455
456         *ret = m;
457         m = NULL;
458
459         return 0;
460 }
461
462 void manager_free(Manager *m) {
463         Network *network;
464         NetDev *netdev;
465         Link *link;
466         AddressPool *pool;
467
468         if (!m)
469                 return;
470
471         free(m->state_file);
472
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);
480
481         while ((link = hashmap_first(m->links)))
482                 link_unref(link);
483         hashmap_free(m->links);
484
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
500 int 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);
507         if (r < 0)
508                 return r;
509
510         r = network_load(m);
511         if (r < 0)
512                 return r;
513
514         return 0;
515 }
516
517 bool manager_should_reload(Manager *m) {
518         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
519 }
520
521 int manager_rtnl_enumerate_links(Manager *m) {
522         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
523         sd_rtnl_message *link;
524         int r;
525
526         assert(m);
527         assert(m->rtnl);
528
529         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
530         if (r < 0)
531                 return r;
532
533         r = sd_rtnl_message_request_dump(req, true);
534         if (r < 0)
535                 return r;
536
537         r = sd_rtnl_call(m->rtnl, req, 0, &reply);
538         if (r < 0)
539                 return r;
540
541         for (link = reply; link; link = sd_rtnl_message_next(link)) {
542                 int k;
543
544                 m->enumerating = true;
545
546                 k = manager_rtnl_process_link(m->rtnl, link, m);
547                 if (k < 0)
548                         r = k;
549
550                 m->enumerating = false;
551         }
552
553         return r;
554 }
555
556 int manager_rtnl_enumerate_addresses(Manager *m) {
557         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
558         sd_rtnl_message *addr;
559         int r;
560
561         assert(m);
562         assert(m->rtnl);
563
564         r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
565         if (r < 0)
566                 return r;
567
568         r = sd_rtnl_message_request_dump(req, true);
569         if (r < 0)
570                 return r;
571
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
579                 m->enumerating = true;
580
581                 k = link_rtnl_process_address(m->rtnl, addr, m);
582                 if (k < 0)
583                         r = k;
584
585                 m->enumerating = false;
586         }
587
588         return r;
589 }
590
591 static 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
608 static 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
625 static 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
644 int manager_save(Manager *m) {
645         _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
646         Link *link;
647         Iterator i;
648         _cleanup_free_ char *temp_path = NULL;
649         _cleanup_fclose_ FILE *f = NULL;
650         LinkOperationalState operstate = LINK_OPERSTATE_OFF;
651         const char *operstate_str;
652         int r;
653
654         assert(m);
655         assert(m->state_file);
656
657         /* We add all NTP and DNS server to a set, to filter out duplicates */
658         dns = set_new(&string_hash_ops);
659         if (!dns)
660                 return -ENOMEM;
661
662         ntp = set_new(&string_hash_ops);
663         if (!ntp)
664                 return -ENOMEM;
665
666         domains = set_new(&string_hash_ops);
667         if (!domains)
668                 return -ENOMEM;
669
670         HASHMAP_FOREACH(link, m->links, i) {
671                 if (link->flags & IFF_LOOPBACK)
672                         continue;
673
674                 if (link->operstate > operstate)
675                         operstate = link->operstate;
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
689                 r = set_put_strdupv(domains, link->network->domains);
690                 if (r < 0)
691                         return r;
692
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;
705                         } else if (r < 0 && r != -ENOENT)
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;
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;
729                         } else if (r != -ENOENT)
730                                 return r;
731                 }
732         }
733
734         operstate_str = link_operstate_to_string(operstate);
735         assert(operstate_str);
736
737         r = fopen_temporary(m->state_file, &f, &temp_path);
738         if (r < 0)
739                 return r;
740
741         fchmod(fileno(f), 0644);
742
743         fprintf(f,
744                 "# This is private data. Do not parse.\n"
745                 "OPER_STATE=%s\n", operstate_str);
746
747         print_string_set(f, "DNS=", dns);
748         print_string_set(f, "NTP=", ntp);
749         print_string_set(f, "DOMAINS=", domains);
750
751         r = fflush_and_check(f);
752         if (r < 0)
753                 goto fail;
754
755         if (rename(temp_path, m->state_file) < 0) {
756                 r = -errno;
757                 goto fail;
758         }
759
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
767         return 0;
768
769 fail:
770         log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
771         unlink(m->state_file);
772         unlink(temp_path);
773         return r;
774 }
775
776 int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
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 }
795
796 const 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
809 AddressFamilyBoolean 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 }
827
828 DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");