]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
networkd: add network_get_by_name
[thirdparty/systemd.git] / src / network / networkd-manager.c
CommitLineData
f579559b
TG
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
091a364c 22#include <sys/socket.h>
bbf7c048 23#include <linux/if.h>
3bef724f 24
2dcf7ec6 25#include "conf-parser.h"
f579559b
TG
26#include "path-util.h"
27#include "networkd.h"
3be1d7e0 28#include "networkd-netdev.h"
0b1831c2 29#include "networkd-link.h"
e16cb2e4 30#include "network-internal.h"
f579559b 31#include "libudev-private.h"
7b77ed8c 32#include "udev-util.h"
50add290 33#include "rtnl-util.h"
a97dcc12
TG
34#include "bus-util.h"
35#include "def.h"
3bef724f 36#include "mkdir.h"
60ad0c85 37#include "virt.h"
f579559b 38
505f8da7 39#include "sd-rtnl.h"
5544ee85 40#include "sd-daemon.h"
505f8da7 41
be660c37
AR
42/* use 8 MB for receive socket kernel queue. */
43#define RCVBUF_SIZE (8*1024*1024)
44
2ad8416d
ZJS
45const char* const network_dirs[] = {
46 "/etc/systemd/network",
47 "/run/systemd/network",
48 "/usr/lib/systemd/network",
eed0eee8 49#ifdef HAVE_SPLIT_USR
2ad8416d
ZJS
50 "/lib/systemd/network",
51#endif
52 NULL};
53
11bf3cce
LP
54static 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
9c0a72f9
TG
81static int on_bus_retry(sd_event_source *s, usec_t usec, void *userdata) {
82 Manager *m = userdata;
83
84 assert(s);
85 assert(m);
86
87 m->bus_retry_event_source = sd_event_source_unref(m->bus_retry_event_source);
88
89 manager_connect_bus(m);
90
91 return 0;
92}
93
94static int manager_reset_all(Manager *m) {
95 Link *link;
96 Iterator i;
97 int r;
98
99 assert(m);
100
101 HASHMAP_FOREACH(link, m->links, i) {
102 r = link_carrier_reset(link);
103 if (r < 0)
104 log_link_warning_errno(link, r, "could not reset carrier: %m");
105 }
106
107 return 0;
108}
109
110static int match_prepare_for_sleep(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
111 Manager *m = userdata;
112 int b, r;
113
114 assert(bus);
115 assert(bus);
116
117 r = sd_bus_message_read(message, "b", &b);
118 if (r < 0) {
119 log_debug_errno(r, "Failed to parse PrepareForSleep signal: %m");
120 return 0;
121 }
122
123 if (b)
124 return 0;
125
126 log_debug("Coming back from suspend, resetting all connections...");
127
128 manager_reset_all(m);
129
130 return 0;
131}
132
133int manager_connect_bus(Manager *m) {
134 int r;
135
136 assert(m);
137
138 r = sd_bus_default_system(&m->bus);
139 if (r == -ENOENT) {
140 /* We failed to connect? Yuck, we must be in early
141 * boot. Let's try in 5s again. As soon as we have
142 * kdbus we can stop doing this... */
143
144 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
145
146 r = sd_event_add_time(m->event, &m->bus_retry_event_source, CLOCK_MONOTONIC, now(CLOCK_MONOTONIC) + 5*USEC_PER_SEC, 0, on_bus_retry, m);
147 if (r < 0)
148 return log_error_errno(r, "Failed to install bus reconnect time event: %m");
149
150 return 0;
151 } if (r < 0)
152 return r;
153
9c0a72f9
TG
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
e331e246
TG
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
9c0a72f9
TG
185 return 0;
186}
187
5fae368b
TG
188static int manager_udev_process_link(Manager *m, struct udev_device *device) {
189 Link *link = NULL;
190 int r, ifindex;
5544ee85 191
5fae368b
TG
192 assert(m);
193 assert(device);
5544ee85 194
5fae368b
TG
195 if (!streq_ptr(udev_device_get_action(device), "add"))
196 return 0;
5544ee85 197
5fae368b
TG
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;
5544ee85
TG
202 }
203
5fae368b
TG
204 r = link_get(m, ifindex, &link);
205 if (r == -ENODEV)
206 return 0;
207 else if (r < 0)
f579559b
TG
208 return r;
209
5fae368b 210 r = link_initialized(link, device);
44de0efc
LP
211 if (r < 0)
212 return r;
213
5fae368b
TG
214 return 0;
215}
be660c37 216
5fae368b
TG
217static 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;
f579559b 221
5fae368b
TG
222 device = udev_monitor_receive_device(monitor);
223 if (!device)
02b59d57
TG
224 return -ENOMEM;
225
5fae368b 226 manager_udev_process_link(m, device);
f579559b
TG
227 return 0;
228}
229
5fae368b
TG
230static int manager_connect_udev(Manager *m) {
231 int r;
f579559b 232
5fae368b
TG
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;
f579559b 238
5fae368b
TG
239 m->udev = udev_new();
240 if (!m->udev)
241 return -ENOMEM;
02b59d57 242
5fae368b
TG
243 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
244 if (!m->udev_monitor)
245 return -ENOMEM;
02b59d57 246
5fae368b 247 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
02b59d57 248 if (r < 0)
5fae368b 249 return log_error_errno(r, "Could not add udev monitor filter: %m");
02b59d57 250
5fae368b
TG
251 r = udev_monitor_enable_receiving(m->udev_monitor);
252 if (r < 0) {
253 log_error("Could not enable udev monitor");
02b59d57 254 return r;
667fcc6d 255 }
505f8da7 256
5fae368b
TG
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)
667fcc6d 263 return r;
505f8da7 264
5fae368b 265 r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
505f8da7
TG
266 if (r < 0)
267 return r;
11a7f229 268
505f8da7
TG
269 return 0;
270}
f579559b 271
505f8da7
TG
272static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
273 Manager *m = userdata;
274 Link *link = NULL;
4d473d5d 275 NetDev *netdev = NULL;
f2236469 276 uint16_t type;
ca4e095a 277 const char *name;
505f8da7 278 int r, ifindex;
f579559b 279
505f8da7
TG
280 assert(rtnl);
281 assert(message);
f579559b
TG
282 assert(m);
283
45af44d4
TG
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
f2236469
TG
292 r = sd_rtnl_message_get_type(message, &type);
293 if (r < 0) {
45af44d4 294 log_warning_errno(r, "rtnl: could not get message type: %m");
f2236469
TG
295 return 0;
296 }
297
505f8da7 298 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
45af44d4
TG
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);
505f8da7 304 return 0;
4d473d5d
TG
305 } else
306 link_get(m, ifindex, &link);
f579559b 307
505f8da7 308 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
45af44d4
TG
309 if (r < 0) {
310 log_warning_errno(r, "rtnl: received link message without ifname: %m");
4d473d5d
TG
311 return 0;
312 } else
f2236469 313 netdev_get(m, name, &netdev);
4d473d5d
TG
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) {
17d1f37d 321 log_warning_errno(r, "could not add new link: %m");
4d473d5d
TG
322 return 0;
323 }
324 }
325
326 if (netdev) {
327 /* netdev exists, so make sure the ifindex matches */
505f8da7
TG
328 r = netdev_set_ifindex(netdev, message);
329 if (r < 0) {
17d1f37d 330 log_warning_errno(r, "could not set ifindex on netdev: %m");
505f8da7
TG
331 return 0;
332 }
333 }
e1202047 334
f2236469
TG
335 r = link_update(link, message);
336 if (r < 0)
337 return 0;
4d473d5d
TG
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.");
f2236469 349 }
505f8da7
TG
350
351 return 1;
352}
353
5fae368b
TG
354static 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
373static int manager_connect_rtnl(Manager *m) {
374 int fd, r;
505f8da7
TG
375
376 assert(m);
505f8da7 377
5fae368b
TG
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);
505f8da7
TG
383 if (r < 0)
384 return r;
385
5fae368b 386 r = sd_rtnl_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
f579559b 387 if (r < 0)
bf5332d2 388 return r;
f579559b 389
5fae368b 390 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
505f8da7
TG
391 if (r < 0)
392 return r;
f579559b 393
5fae368b
TG
394 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
395 if (r < 0)
396 return r;
505f8da7 397
5fae368b
TG
398 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
399 if (r < 0)
400 return r;
45af44d4 401
5fae368b
TG
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;
45af44d4 411}
505f8da7 412
5fae368b
TG
413int manager_new(Manager **ret) {
414 _cleanup_manager_free_ Manager *m = NULL;
45af44d4 415 int r;
f579559b 416
5fae368b
TG
417 m = new0(Manager, 1);
418 if (!m)
419 return -ENOMEM;
45af44d4 420
5fae368b
TG
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);
45af44d4
TG
426 if (r < 0)
427 return r;
428
5fae368b
TG
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);
45af44d4
TG
435 if (r < 0)
436 return r;
437
5fae368b
TG
438 r = manager_connect_udev(m);
439 if (r < 0)
440 return r;
45af44d4 441
5fae368b
TG
442 m->netdevs = hashmap_new(&string_hash_ops);
443 if (!m->netdevs)
444 return -ENOMEM;
f579559b 445
5fae368b 446 LIST_HEAD_INIT(m->networks);
f579559b 447
5fae368b
TG
448 r = setup_default_address_pool(m);
449 if (r < 0)
450 return r;
f579559b 451
5fae368b
TG
452 *ret = m;
453 m = NULL;
f579559b 454
f579559b
TG
455 return 0;
456}
457
5fae368b
TG
458void manager_free(Manager *m) {
459 Network *network;
460 NetDev *netdev;
461 Link *link;
462 AddressPool *pool;
f579559b 463
5fae368b
TG
464 if (!m)
465 return;
505f8da7 466
5fae368b 467 free(m->state_file);
505f8da7 468
5fae368b
TG
469 udev_monitor_unref(m->udev_monitor);
470 udev_unref(m->udev);
471 sd_bus_unref(m->bus);
472 sd_bus_slot_unref(m->prepare_for_sleep_slot);
473 sd_event_source_unref(m->udev_event_source);
474 sd_event_source_unref(m->bus_retry_event_source);
475 sd_event_unref(m->event);
f579559b 476
5fae368b
TG
477 while ((link = hashmap_first(m->links)))
478 link_unref(link);
479 hashmap_free(m->links);
f579559b 480
5fae368b
TG
481 while ((network = m->networks))
482 network_free(network);
483
dbffab87
TG
484 hashmap_free(m->networks_by_name);
485
5fae368b
TG
486 while ((netdev = hashmap_first(m->netdevs)))
487 netdev_unref(netdev);
488 hashmap_free(m->netdevs);
489
490 while ((pool = m->address_pools))
491 address_pool_free(pool);
492
493 sd_rtnl_unref(m->rtnl);
494
495 free(m);
496}
497
a97dcc12
TG
498static bool manager_check_idle(void *userdata) {
499 Manager *m = userdata;
500 Link *link;
501 Iterator i;
502
503 assert(m);
504
505 HASHMAP_FOREACH(link, m->links, i) {
506 /* we are not woken on udev activity, so let's just wait for the
507 * pending udev event */
508 if (link->state == LINK_STATE_PENDING)
509 return false;
510
511 if (!link->network)
512 continue;
513
514 /* we are not woken on netork activity, so let's stay around */
515 if (link_lldp_enabled(link) ||
516 link_ipv4ll_enabled(link) ||
517 link_dhcp4_server_enabled(link) ||
518 link_dhcp4_enabled(link) ||
519 link_dhcp6_enabled(link))
520 return false;
521 }
522
523 return true;
524}
525
526int manager_run(Manager *m) {
527 assert(m);
528
529 return bus_event_loop_with_idle(
530 m->event,
531 m->bus,
532 "org.freedesktop.network1",
533 DEFAULT_EXIT_USEC,
534 manager_check_idle,
535 m);
536}
537
5fae368b
TG
538int manager_load_config(Manager *m) {
539 int r;
540
541 /* update timestamp */
542 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
543
544 r = netdev_load(m);
f579559b
TG
545 if (r < 0)
546 return r;
547
5fae368b 548 r = network_load(m);
9021bb9f
TG
549 if (r < 0)
550 return r;
551
f579559b
TG
552 return 0;
553}
f882c247 554
5fae368b
TG
555bool manager_should_reload(Manager *m) {
556 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
557}
558
559int manager_rtnl_enumerate_links(Manager *m) {
560 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
561 sd_rtnl_message *link;
f882c247
TG
562 int r;
563
5da8149f 564 assert(m);
5fae368b 565 assert(m->rtnl);
5da8149f 566
5fae368b 567 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
f882c247
TG
568 if (r < 0)
569 return r;
570
5fae368b 571 r = sd_rtnl_message_request_dump(req, true);
dd3efc09
TG
572 if (r < 0)
573 return r;
574
5fae368b 575 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
f2236469
TG
576 if (r < 0)
577 return r;
578
5fae368b
TG
579 for (link = reply; link; link = sd_rtnl_message_next(link)) {
580 int k;
2e9f08ea 581
6a24f148
TG
582 m->enumerating = true;
583
5fae368b
TG
584 k = manager_rtnl_process_link(m->rtnl, link, m);
585 if (k < 0)
586 r = k;
6a24f148
TG
587
588 m->enumerating = false;
5fae368b 589 }
2e9f08ea 590
5fae368b 591 return r;
f882c247 592}
3bef724f 593
5fae368b
TG
594int manager_rtnl_enumerate_addresses(Manager *m) {
595 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
596 sd_rtnl_message *addr;
1346b1f0
TG
597 int r;
598
5fae368b
TG
599 assert(m);
600 assert(m->rtnl);
bcbca829 601
5fae368b
TG
602 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
603 if (r < 0)
604 return r;
bcbca829 605
5fae368b 606 r = sd_rtnl_message_request_dump(req, true);
1346b1f0
TG
607 if (r < 0)
608 return r;
609
5fae368b
TG
610 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
611 if (r < 0)
612 return r;
613
614 for (addr = reply; addr; addr = sd_rtnl_message_next(addr)) {
615 int k;
616
6a24f148
TG
617 m->enumerating = true;
618
5fae368b
TG
619 k = link_rtnl_process_address(m->rtnl, addr, m);
620 if (k < 0)
621 r = k;
6a24f148
TG
622
623 m->enumerating = false;
5fae368b
TG
624 }
625
626 return r;
1346b1f0
TG
627}
628
c0c743cb
LP
629static int set_put_in_addr(Set *s, const struct in_addr *address) {
630 char *p;
631 int r;
632
633 assert(s);
634
635 r = in_addr_to_string(AF_INET, (const union in_addr_union*) address, &p);
636 if (r < 0)
637 return r;
638
639 r = set_consume(s, p);
640 if (r == -EEXIST)
641 return 0;
642
643 return r;
644}
645
646static int set_put_in_addrv(Set *s, const struct in_addr *addresses, int n) {
647 int r, i, c = 0;
648
649 assert(s);
650 assert(n <= 0 || addresses);
651
652 for (i = 0; i < n; i++) {
653 r = set_put_in_addr(s, addresses+i);
654 if (r < 0)
655 return r;
656
657 c += r;
658 }
659
660 return c;
661}
662
8612e936
LP
663static void print_string_set(FILE *f, const char *field, Set *s) {
664 bool space = false;
665 Iterator i;
666 char *p;
667
668 if (set_isempty(s))
669 return;
670
671 fputs(field, f);
672
673 SET_FOREACH(p, s, i) {
674 if (space)
675 fputc(' ', f);
676 fputs(p, f);
677 space = true;
678 }
679 fputc('\n', f);
680}
681
bbf7c048 682int manager_save(Manager *m) {
8612e936 683 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
bbf7c048
TG
684 Link *link;
685 Iterator i;
686 _cleanup_free_ char *temp_path = NULL;
687 _cleanup_fclose_ FILE *f = NULL;
d3df0e39 688 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
e375dcde 689 const char *operstate_str;
bbf7c048
TG
690 int r;
691
692 assert(m);
693 assert(m->state_file);
694
c0c743cb 695 /* We add all NTP and DNS server to a set, to filter out duplicates */
d5099efc 696 dns = set_new(&string_hash_ops);
c0c743cb
LP
697 if (!dns)
698 return -ENOMEM;
699
d5099efc 700 ntp = set_new(&string_hash_ops);
c0c743cb
LP
701 if (!ntp)
702 return -ENOMEM;
703
d5099efc 704 domains = set_new(&string_hash_ops);
8612e936
LP
705 if (!domains)
706 return -ENOMEM;
707
bbf7c048
TG
708 HASHMAP_FOREACH(link, m->links, i) {
709 if (link->flags & IFF_LOOPBACK)
710 continue;
711
e375dcde
TG
712 if (link->operstate > operstate)
713 operstate = link->operstate;
c0c743cb
LP
714
715 if (!link->network)
716 continue;
717
718 /* First add the static configured entries */
719 r = set_put_strdupv(dns, link->network->dns);
720 if (r < 0)
721 return r;
722
723 r = set_put_strdupv(ntp, link->network->ntp);
724 if (r < 0)
725 return r;
726
8612e936
LP
727 r = set_put_strdupv(domains, link->network->domains);
728 if (r < 0)
729 return r;
730
c0c743cb
LP
731 if (!link->dhcp_lease)
732 continue;
733
734 /* Secondly, add the entries acquired via DHCP */
735 if (link->network->dhcp_dns) {
736 const struct in_addr *addresses;
737
738 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &addresses);
739 if (r > 0) {
740 r = set_put_in_addrv(dns, addresses, r);
741 if (r < 0)
742 return r;
8612e936 743 } else if (r < 0 && r != -ENOENT)
c0c743cb
LP
744 return r;
745 }
746
747 if (link->network->dhcp_ntp) {
748 const struct in_addr *addresses;
749
750 r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &addresses);
751 if (r > 0) {
752 r = set_put_in_addrv(ntp, addresses, r);
753 if (r < 0)
754 return r;
8612e936
LP
755 } else if (r < 0 && r != -ENOENT)
756 return r;
757 }
758
759 if (link->network->dhcp_domains) {
760 const char *domainname;
761
762 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
763 if (r >= 0) {
764 r = set_put_strdup(domains, domainname);
765 if (r < 0)
766 return r;
c0c743cb
LP
767 } else if (r != -ENOENT)
768 return r;
769 }
bbf7c048
TG
770 }
771
e375dcde
TG
772 operstate_str = link_operstate_to_string(operstate);
773 assert(operstate_str);
bbf7c048
TG
774
775 r = fopen_temporary(m->state_file, &f, &temp_path);
776 if (r < 0)
c2d6bd61 777 return r;
bbf7c048
TG
778
779 fchmod(fileno(f), 0644);
780
781 fprintf(f,
782 "# This is private data. Do not parse.\n"
e375dcde 783 "OPER_STATE=%s\n", operstate_str);
bbf7c048 784
8612e936
LP
785 print_string_set(f, "DNS=", dns);
786 print_string_set(f, "NTP=", ntp);
787 print_string_set(f, "DOMAINS=", domains);
c0c743cb 788
c2d6bd61
LP
789 r = fflush_and_check(f);
790 if (r < 0)
791 goto fail;
bbf7c048 792
c2d6bd61 793 if (rename(temp_path, m->state_file) < 0) {
bbf7c048 794 r = -errno;
c2d6bd61 795 goto fail;
bbf7c048
TG
796 }
797
e331e246
TG
798 if (m->operational_state != operstate) {
799 m->operational_state = operstate;
800 r = manager_send_changed(m, "OperationalState", NULL);
801 if (r < 0)
802 log_error_errno(r, "Could not emit changed OperationalState: %m");
803 }
804
c2d6bd61 805 return 0;
bbf7c048 806
c2d6bd61 807fail:
da927ba9 808 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
c2d6bd61
LP
809 unlink(m->state_file);
810 unlink(temp_path);
bbf7c048
TG
811 return r;
812}
11bf3cce 813
0dd25fb9 814int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce
LP
815 AddressPool *p;
816 int r;
817
818 assert(m);
819 assert(prefixlen > 0);
820 assert(found);
821
822 LIST_FOREACH(address_pools, p, m->address_pools) {
823 if (p->family != family)
824 continue;
825
826 r = address_pool_acquire(p, prefixlen, found);
827 if (r != 0)
828 return r;
829 }
830
831 return 0;
832}
cb9fc36a
LP
833
834const char *address_family_boolean_to_string(AddressFamilyBoolean b) {
835 if (b == ADDRESS_FAMILY_YES ||
836 b == ADDRESS_FAMILY_NO)
837 return yes_no(b == ADDRESS_FAMILY_YES);
838
839 if (b == ADDRESS_FAMILY_IPV4)
840 return "ipv4";
841 if (b == ADDRESS_FAMILY_IPV6)
842 return "ipv6";
843
844 return NULL;
845}
846
847AddressFamilyBoolean address_family_boolean_from_string(const char *s) {
848 int r;
849
850 /* Make this a true superset of a boolean */
851
852 r = parse_boolean(s);
853 if (r > 0)
854 return ADDRESS_FAMILY_YES;
855 if (r == 0)
856 return ADDRESS_FAMILY_NO;
857
858 if (streq(s, "ipv4"))
859 return ADDRESS_FAMILY_IPV4;
860 if (streq(s, "ipv6"))
861 return ADDRESS_FAMILY_IPV6;
862
863 return _ADDRESS_FAMILY_BOOLEAN_INVALID;
864}
769d324c
LP
865
866DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");