]> git.proxmox.com Git - systemd.git/blame - src/network/networkd-manager.c
Imported Upstream version 220
[systemd.git] / src / network / networkd-manager.c
CommitLineData
60f067b4
JS
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"
5eef597e
MP
28#include "networkd-netdev.h"
29#include "networkd-link.h"
60f067b4
JS
30#include "libudev-private.h"
31#include "udev-util.h"
32#include "rtnl-util.h"
e735f4d4
MP
33#include "bus-util.h"
34#include "def.h"
60f067b4
JS
35#include "virt.h"
36
37#include "sd-rtnl.h"
e735f4d4 38#include "sd-daemon.h"
60f067b4 39
f47781d8
MP
40/* use 8 MB for receive socket kernel queue. */
41#define RCVBUF_SIZE (8*1024*1024)
42
60f067b4
JS
43const 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
e842803a
MB
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
e735f4d4
MP
79static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
80 Manager *m = userdata;
60f067b4 81
e735f4d4
MP
82 assert(s);
83 assert(m);
60f067b4 84
e735f4d4 85 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
60f067b4 86
e735f4d4 87 manager_connect_bus(m);
60f067b4 88
e735f4d4
MP
89 return 0;
90}
60f067b4 91
e735f4d4
MP
92static int manager_reset_all(Manager *m) {
93 Link *link;
94 Iterator i;
95 int r;
5eef597e 96
e735f4d4 97 assert(m);
60f067b4 98
e735f4d4
MP
99 HASHMAP_FOREACH(link, m->links, i) {
100 r = link_carrier_reset(link);
101 if (r < 0)
102 log_link_warning_errno(link, r, "could not reset carrier: %m");
103 }
f47781d8 104
e735f4d4
MP
105 return 0;
106}
60f067b4 107
e3bff60a 108static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
e735f4d4
MP
109 Manager *m = userdata;
110 int b, r;
60f067b4 111
e3bff60a 112 assert(message);
60f067b4 113
e735f4d4
MP
114 r = sd_bus_message_read(message, "b", &b);
115 if (r < 0) {
116 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
117 return 0;
118 }
60f067b4 119
e735f4d4
MP
120 if (b)
121 return 0;
e842803a 122
e735f4d4
MP
123 log_debug("Coming back from suspend, resetting all connections...");
124
125 manager_reset_all(m);
60f067b4
JS
126
127 return 0;
128}
129
e735f4d4
MP
130int manager_connect_bus(Manager *m) {
131 int r;
60f067b4 132
e735f4d4 133 assert(m);
60f067b4 134
e735f4d4
MP
135 r = sd_bus_default_system(&m->bus);
136 if (r == -ENOENT) {
137 /* We failed to connect? Yuck, we must be in early
138 * boot. Let's try in 5s again. As soon as we have
139 * kdbus we can stop doing this... */
60f067b4 140
e735f4d4 141 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
60f067b4 142
e735f4d4
MP
143 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);
144 if (r < 0)
145 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
60f067b4 146
e735f4d4
MP
147 return 0;
148 } if (r < 0)
149 return r;
60f067b4 150
e735f4d4
MP
151 r = sd_bus_add_match(m->bus, &m->prepare_for_sleep_slot,
152 "type='signal',"
153 "sender='org.freedesktop.login1',"
154 "interface='org.freedesktop.login1.Manager',"
155 "member='PrepareForSleep',"
156 "path='/org/freedesktop/login1'",
157 match_prepare_for_sleep,
158 m);
159 if (r < 0)
160 return log_error_errno(r, "Failed to add match for PrepareForSleep: %m");
60f067b4 161
e735f4d4
MP
162 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/network1", "org.freedesktop.network1.Manager", manager_vtable, m);
163 if (r < 0)
164 return log_error_errno(r, "Failed to add manager object vtable: %m");
e842803a 165
e735f4d4
MP
166 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/link", "org.freedesktop.network1.Link", link_vtable, link_object_find, m);
167 if (r < 0)
168 return log_error_errno(r, "Failed to add link object vtable: %m");
60f067b4 169
e735f4d4
MP
170 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/link", link_node_enumerator, m);
171 if (r < 0)
172 return log_error_errno(r, "Failed to add link enumerator: %m");
60f067b4 173
e735f4d4
MP
174 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/network1/network", "org.freedesktop.network1.Network", network_vtable, network_object_find, m);
175 if (r < 0)
176 return log_error_errno(r, "Failed to add network object vtable: %m");
60f067b4 177
e735f4d4
MP
178 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/network1/network", network_node_enumerator, m);
179 if (r < 0)
180 return log_error_errno(r, "Failed to add network enumerator: %m");
60f067b4 181
e735f4d4 182 r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
60f067b4 183 if (r < 0)
e735f4d4 184 return log_error_errno(r, "Failed to register name: %m");
60f067b4 185
e735f4d4 186 r = sd_bus_attach_event(m->bus, m->event, 0);
60f067b4 187 if (r < 0)
e735f4d4 188 return log_error_errno(r, "Failed to attach bus to event loop: %m");
60f067b4
JS
189
190 return 0;
191}
192
60f067b4
JS
193static int manager_udev_process_link(Manager *m, struct udev_device *device) {
194 Link *link = NULL;
195 int r, ifindex;
196
197 assert(m);
198 assert(device);
199
200 if (!streq_ptr(udev_device_get_action(device), "add"))
201 return 0;
202
203 ifindex = udev_device_get_ifindex(device);
204 if (ifindex <= 0) {
205 log_debug("ignoring udev ADD event for device with invalid ifindex");
206 return 0;
207 }
208
209 r = link_get(m, ifindex, &link);
210 if (r == -ENODEV)
211 return 0;
212 else if (r < 0)
213 return r;
214
215 r = link_initialized(link, device);
216 if (r < 0)
217 return r;
218
219 return 0;
220}
221
e735f4d4
MP
222static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
223 Manager *m = userdata;
224 struct udev_monitor *monitor = m->udev_monitor;
225 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
226
227 device = udev_monitor_receive_device(monitor);
228 if (!device)
229 return -ENOMEM;
230
231 manager_udev_process_link(m, device);
232 return 0;
233}
234
235static int manager_connect_udev(Manager *m) {
236 int r;
237
238 /* udev does not initialize devices inside containers,
239 * so we rely on them being already initialized before
240 * entering the container */
241 if (detect_container(NULL) > 0)
242 return 0;
243
244 m->udev = udev_new();
245 if (!m->udev)
246 return -ENOMEM;
247
248 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
249 if (!m->udev_monitor)
250 return -ENOMEM;
251
252 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
253 if (r < 0)
254 return log_error_errno(r, "Could not add udev monitor filter: %m");
255
256 r = udev_monitor_enable_receiving(m->udev_monitor);
257 if (r < 0) {
258 log_error("Could not enable udev monitor");
259 return r;
260 }
261
262 r = sd_event_add_io(m->event,
263 &m->udev_event_source,
264 udev_monitor_get_fd(m->udev_monitor),
265 EPOLLIN, manager_dispatch_link_udev,
266 m);
267 if (r < 0)
268 return r;
269
270 r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
271 if (r < 0)
272 return r;
273
274 return 0;
275}
276
60f067b4
JS
277static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
278 Manager *m = userdata;
279 Link *link = NULL;
280 NetDev *netdev = NULL;
281 uint16_t type;
5eef597e 282 const char *name;
60f067b4
JS
283 int r, ifindex;
284
285 assert(rtnl);
286 assert(message);
287 assert(m);
288
f47781d8
MP
289 if (sd_rtnl_message_is_error(message)) {
290 r = sd_rtnl_message_get_errno(message);
291 if (r < 0)
292 log_warning_errno(r, "rtnl: could not receive link: %m");
293
294 return 0;
295 }
296
60f067b4
JS
297 r = sd_rtnl_message_get_type(message, &type);
298 if (r < 0) {
f47781d8 299 log_warning_errno(r, "rtnl: could not get message type: %m");
60f067b4 300 return 0;
e3bff60a
MP
301 } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
302 log_warning("rtnl: received unexpected message type when processing link");
303 return 0;
60f067b4
JS
304 }
305
306 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
f47781d8 307 if (r < 0) {
e3bff60a 308 log_warning_errno(r, "rtnl: could not get ifindex from link: %m");
f47781d8
MP
309 return 0;
310 } else if (ifindex <= 0) {
311 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
60f067b4
JS
312 return 0;
313 } else
314 link_get(m, ifindex, &link);
315
316 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
f47781d8
MP
317 if (r < 0) {
318 log_warning_errno(r, "rtnl: received link message without ifname: %m");
60f067b4
JS
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) {
e735f4d4 329 log_warning_errno(r, "could not add new link: %m");
60f067b4
JS
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) {
e735f4d4 338 log_warning_errno(r, "could not set ifindex on netdev: %m");
60f067b4
JS
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
e735f4d4
MP
362static 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
381static int manager_connect_rtnl(Manager *m) {
382 int fd, r;
60f067b4
JS
383
384 assert(m);
60f067b4 385
e735f4d4
MP
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);
60f067b4
JS
391 if (r < 0)
392 return r;
393
e735f4d4 394 r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
60f067b4
JS
395 if (r < 0)
396 return r;
397
e735f4d4 398 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
60f067b4
JS
399 if (r < 0)
400 return r;
401
e735f4d4
MP
402 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
403 if (r < 0)
404 return r;
60f067b4 405
e735f4d4
MP
406 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
407 if (r < 0)
408 return r;
60f067b4 409
e735f4d4
MP
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;
f47781d8 419}
60f067b4 420
e735f4d4
MP
421int manager_new(Manager **ret) {
422 _cleanup_manager_free_ Manager *m = NULL;
f47781d8
MP
423 int r;
424
e735f4d4
MP
425 m = new0(Manager, 1);
426 if (!m)
427 return -ENOMEM;
f47781d8 428
e735f4d4
MP
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);
f47781d8
MP
434 if (r < 0)
435 return r;
436
e735f4d4
MP
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);
f47781d8
MP
443 if (r < 0)
444 return r;
445
e735f4d4 446 r = manager_connect_udev(m);
f47781d8
MP
447 if (r < 0)
448 return r;
449
e735f4d4
MP
450 m->netdevs = hashmap_new(&string_hash_ops);
451 if (!m->netdevs)
452 return -ENOMEM;
f47781d8 453
e735f4d4 454 LIST_HEAD_INIT(m->networks);
60f067b4 455
e735f4d4
MP
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;
60f067b4
JS
464}
465
e735f4d4
MP
466void manager_free(Manager *m) {
467 Network *network;
468 NetDev *netdev;
469 Link *link;
470 AddressPool *pool;
60f067b4 471
e735f4d4
MP
472 if (!m)
473 return;
60f067b4 474
e735f4d4
MP
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);
60f067b4
JS
504}
505
e735f4d4
MP
506static bool manager_check_idle(void *userdata) {
507 Manager *m = userdata;
508 Link *link;
509 Iterator i;
60f067b4 510
e735f4d4 511 assert(m);
60f067b4 512
e735f4d4
MP
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;
60f067b4 518
e735f4d4
MP
519 if (!link->network)
520 continue;
60f067b4 521
e735f4d4
MP
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;
60f067b4
JS
529 }
530
e735f4d4
MP
531 return true;
532}
533
534int manager_run(Manager *m) {
535 assert(m);
536
537 if (m->bus)
538 return bus_event_loop_with_idle(
539 m->event,
540 m->bus,
541 "org.freedesktop.network1",
542 DEFAULT_EXIT_USEC,
543 manager_check_idle,
544 m);
545 else
546 /* failed to connect to the bus, so we lose exit-on-idle logic,
547 this should not happen except if dbus is not around at all */
548 return sd_event_loop(m->event);
549}
550
551int manager_load_config(Manager *m) {
552 int r;
553
554 /* update timestamp */
555 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
556
557 r = netdev_load(m);
60f067b4
JS
558 if (r < 0)
559 return r;
560
e735f4d4 561 r = network_load(m);
5eef597e
MP
562 if (r < 0)
563 return r;
564
60f067b4
JS
565 return 0;
566}
567
e735f4d4
MP
568bool manager_should_reload(Manager *m) {
569 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
570}
571
572int manager_rtnl_enumerate_links(Manager *m) {
573 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
574 sd_rtnl_message *link;
60f067b4
JS
575 int r;
576
e842803a 577 assert(m);
e735f4d4 578 assert(m->rtnl);
e842803a 579
e735f4d4 580 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
60f067b4
JS
581 if (r < 0)
582 return r;
583
e735f4d4 584 r = sd_rtnl_message_request_dump(req, true);
60f067b4
JS
585 if (r < 0)
586 return r;
587
e735f4d4 588 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
60f067b4
JS
589 if (r < 0)
590 return r;
591
e735f4d4
MP
592 for (link = reply; link; link = sd_rtnl_message_next(link)) {
593 int k;
60f067b4 594
e735f4d4 595 m->enumerating = true;
60f067b4 596
e735f4d4
MP
597 k = manager_rtnl_process_link(m->rtnl, link, m);
598 if (k < 0)
599 r = k;
600
601 m->enumerating = false;
602 }
603
604 return r;
60f067b4
JS
605}
606
e735f4d4
MP
607int manager_rtnl_enumerate_addresses(Manager *m) {
608 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
609 sd_rtnl_message *addr;
60f067b4
JS
610 int r;
611
e735f4d4
MP
612 assert(m);
613 assert(m->rtnl);
60f067b4 614
e735f4d4
MP
615 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
616 if (r < 0)
617 return r;
60f067b4 618
e735f4d4 619 r = sd_rtnl_message_request_dump(req, true);
60f067b4
JS
620 if (r < 0)
621 return r;
622
e735f4d4
MP
623 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
624 if (r < 0)
625 return r;
626
627 for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
628 int k;
629
630 m->enumerating = true;
631
632 k = link_rtnl_process_address(m->rtnl, addr, m);
633 if (k < 0)
634 r = k;
635
636 m->enumerating = false;
637 }
638
639 return r;
60f067b4
JS
640}
641
5eef597e
MP
642static int set_put_in_addr(Set *s, const struct in_addr *address) {
643 char *p;
644 int r;
645
646 assert(s);
647
648 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
649 if (r < 0)
650 return r;
651
652 r = set_consume(s, p);
653 if (r == -EEXIST)
654 return 0;
655
656 return r;
657}
658
659static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
660 int r, i, c = 0;
661
662 assert(s);
663 assert(n <= 0 || addresses);
664
665 for (i = 0; i < n; i++) {
666 r = set_put_in_addr(s, addresses+i);
667 if (r < 0)
668 return r;
669
670 c += r;
671 }
672
673 return c;
674}
675
676static void print_string_set(FILE *f, const char *field, Set *s) {
677 bool space = false;
678 Iterator i;
679 char *p;
680
681 if (set_isempty(s))
682 return;
683
684 fputs(field, f);
685
686 SET_FOREACH(p, s, i) {
687 if (space)
688 fputc(' ', f);
689 fputs(p, f);
690 space = true;
691 }
692 fputc('\n', f);
693}
694
60f067b4 695int manager_save(Manager *m) {
5eef597e 696 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
60f067b4
JS
697 Link *link;
698 Iterator i;
699 _cleanup_free_ char *temp_path = NULL;
700 _cleanup_fclose_ FILE *f = NULL;
5eef597e 701 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
60f067b4
JS
702 const char *operstate_str;
703 int r;
704
705 assert(m);
706 assert(m->state_file);
707
5eef597e
MP
708 /* We add all NTP and DNS server to a set, to filter out duplicates */
709 dns = set_new(&string_hash_ops);
710 if (!dns)
711 return -ENOMEM;
712
713 ntp = set_new(&string_hash_ops);
714 if (!ntp)
715 return -ENOMEM;
716
717 domains = set_new(&string_hash_ops);
718 if (!domains)
719 return -ENOMEM;
720
60f067b4
JS
721 HASHMAP_FOREACH(link, m->links, i) {
722 if (link->flags & IFF_LOOPBACK)
723 continue;
724
725 if (link->operstate > operstate)
726 operstate = link->operstate;
5eef597e
MP
727
728 if (!link->network)
729 continue;
730
731 /* First add the static configured entries */
732 r = set_put_strdupv(dns, link->network->dns);
733 if (r < 0)
734 return r;
735
736 r = set_put_strdupv(ntp, link->network->ntp);
737 if (r < 0)
738 return r;
739
740 r = set_put_strdupv(domains, link->network->domains);
741 if (r < 0)
742 return r;
743
744 if (!link->dhcp_lease)
745 continue;
746
747 /* Secondly, add the entries acquired via DHCP */
748 if (link->network->dhcp_dns) {
749 const struct in_addr *addresses;
750
751 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
752 if (r > 0) {
753 r = set_put_in_addrv(dns, addresses, r);
754 if (r < 0)
755 return r;
756 } else if (r < 0 && r != -ENOENT)
757 return r;
758 }
759
760 if (link->network->dhcp_ntp) {
761 const struct in_addr *addresses;
762
763 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
764 if (r > 0) {
765 r = set_put_in_addrv(ntp, addresses, r);
766 if (r < 0)
767 return r;
768 } else if (r < 0 && r != -ENOENT)
769 return r;
770 }
771
772 if (link->network->dhcp_domains) {
773 const char *domainname;
774
775 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
776 if (r >= 0) {
777 r = set_put_strdup(domains, domainname);
778 if (r < 0)
779 return r;
780 } else if (r != -ENOENT)
781 return r;
782 }
60f067b4
JS
783 }
784
785 operstate_str = link_operstate_to_string(operstate);
786 assert(operstate_str);
787
788 r = fopen_temporary(m->state_file, &f, &temp_path);
789 if (r < 0)
5eef597e 790 return r;
60f067b4
JS
791
792 fchmod(fileno(f), 0644);
793
794 fprintf(f,
795 "# This is private data. Do not parse.\n"
796 "OPER_STATE=%s\n", operstate_str);
797
5eef597e
MP
798 print_string_set(f, "DNS=", dns);
799 print_string_set(f, "NTP=", ntp);
800 print_string_set(f, "DOMAINS=", domains);
801
802 r = fflush_and_check(f);
803 if (r < 0)
804 goto fail;
60f067b4 805
5eef597e 806 if (rename(temp_path, m->state_file) < 0) {
60f067b4 807 r = -errno;
5eef597e 808 goto fail;
60f067b4
JS
809 }
810
e735f4d4
MP
811 if (m->operational_state != operstate) {
812 m->operational_state = operstate;
813 r = manager_send_changed(m, "OperationalState", NULL);
814 if (r < 0)
815 log_error_errno(r, "Could not emit changed OperationalState: %m");
816 }
817
5eef597e 818 return 0;
60f067b4 819
5eef597e 820fail:
f47781d8 821 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
5eef597e
MP
822 unlink(m->state_file);
823 unlink(temp_path);
60f067b4
JS
824 return r;
825}
e842803a 826
5eef597e 827int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
e842803a
MB
828 AddressPool *p;
829 int r;
830
831 assert(m);
832 assert(prefixlen > 0);
833 assert(found);
834
835 LIST_FOREACH(address_pools, p, m->address_pools) {
836 if (p->family != family)
837 continue;
838
839 r = address_pool_acquire(p, prefixlen, found);
840 if (r != 0)
841 return r;
842 }
843
844 return 0;
845}
e735f4d4
MP
846
847const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
848 if (b == ADDRESS_FAMILY_YES ||
849 b == ADDRESS_FAMILY_NO)
850 return yes_no(b == ADDRESS_FAMILY_YES);
851
852 if (b == ADDRESS_FAMILY_IPV4)
853 return "ipv4";
854 if (b == ADDRESS_FAMILY_IPV6)
855 return "ipv6";
856
857 return NULL;
858}
859
860AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
861 int r;
862
863 /* Make this a true superset of a boolean */
864
865 r = parse_boolean(s);
866 if (r > 0)
867 return ADDRESS_FAMILY_YES;
868 if (r == 0)
869 return ADDRESS_FAMILY_NO;
870
871 if (streq(s, "ipv4"))
872 return ADDRESS_FAMILY_IPV4;
873 if (streq(s, "ipv6"))
874 return ADDRESS_FAMILY_IPV6;
875
876 return _ADDRESS_FAMILY_BOOLEAN_INVALID;
877}
878
879DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");