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