]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
build-sys: fix "make doc-sync"
[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"
1c4baffc 32#include "netlink-util.h"
a97dcc12
TG
33#include "bus-util.h"
34#include "def.h"
60ad0c85 35#include "virt.h"
f579559b 36
1c4baffc 37#include "sd-netlink.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
19070062 108static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
9c0a72f9
TG
109 Manager *m = userdata;
110 int b, r;
111
19070062 112 assert(message);
9c0a72f9
TG
113
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 }
119
120 if (b)
121 return 0;
122
123 log_debug("Coming back from suspend, resetting all connections...");
124
125 manager_reset_all(m);
126
127 return 0;
128}
129
130int manager_connect_bus(Manager *m) {
131 int r;
132
133 assert(m);
134
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... */
140
141 log_debug_errno(r, "Failed to connect to bus, trying again in 5s: %m");
142
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");
146
147 return 0;
148 } if (r < 0)
149 return r;
150
9c0a72f9
TG
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");
161
e331e246
TG
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");
165
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");
169
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");
3175fcde
TG
173
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");
177
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");
e331e246
TG
181
182 r = sd_bus_request_name(m->bus, "org.freedesktop.network1", 0);
183 if (r < 0)
184 return log_error_errno(r, "Failed to register name: %m");
185
186 r = sd_bus_attach_event(m->bus, m->event, 0);
187 if (r < 0)
188 return log_error_errno(r, "Failed to attach bus to event loop: %m");
189
9c0a72f9
TG
190 return 0;
191}
192
5fae368b
TG
193static int manager_udev_process_link(Manager *m, struct udev_device *device) {
194 Link *link = NULL;
195 int r, ifindex;
5544ee85 196
5fae368b
TG
197 assert(m);
198 assert(device);
5544ee85 199
5fae368b
TG
200 if (!streq_ptr(udev_device_get_action(device), "add"))
201 return 0;
5544ee85 202
5fae368b
TG
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;
5544ee85
TG
207 }
208
5fae368b
TG
209 r = link_get(m, ifindex, &link);
210 if (r == -ENODEV)
211 return 0;
212 else if (r < 0)
f579559b
TG
213 return r;
214
5fae368b 215 r = link_initialized(link, device);
44de0efc
LP
216 if (r < 0)
217 return r;
218
5fae368b
TG
219 return 0;
220}
be660c37 221
5fae368b
TG
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;
f579559b 226
5fae368b
TG
227 device = udev_monitor_receive_device(monitor);
228 if (!device)
02b59d57
TG
229 return -ENOMEM;
230
5fae368b 231 manager_udev_process_link(m, device);
f579559b
TG
232 return 0;
233}
234
5fae368b
TG
235static int manager_connect_udev(Manager *m) {
236 int r;
f579559b 237
5fae368b
TG
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;
f579559b 243
5fae368b
TG
244 m->udev = udev_new();
245 if (!m->udev)
246 return -ENOMEM;
02b59d57 247
5fae368b
TG
248 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
249 if (!m->udev_monitor)
250 return -ENOMEM;
02b59d57 251
5fae368b 252 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
02b59d57 253 if (r < 0)
5fae368b 254 return log_error_errno(r, "Could not add udev monitor filter: %m");
02b59d57 255
5fae368b
TG
256 r = udev_monitor_enable_receiving(m->udev_monitor);
257 if (r < 0) {
258 log_error("Could not enable udev monitor");
02b59d57 259 return r;
667fcc6d 260 }
505f8da7 261
5fae368b
TG
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)
667fcc6d 268 return r;
505f8da7 269
5fae368b 270 r = sd_event_source_set_description(m->udev_event_source, "networkd-udev");
505f8da7
TG
271 if (r < 0)
272 return r;
11a7f229 273
505f8da7
TG
274 return 0;
275}
f579559b 276
1c4baffc 277static int manager_rtnl_process_link(sd_netlink *rtnl, sd_netlink_message *message, void *userdata) {
505f8da7
TG
278 Manager *m = userdata;
279 Link *link = NULL;
4d473d5d 280 NetDev *netdev = NULL;
f2236469 281 uint16_t type;
ca4e095a 282 const char *name;
505f8da7 283 int r, ifindex;
f579559b 284
505f8da7
TG
285 assert(rtnl);
286 assert(message);
f579559b
TG
287 assert(m);
288
1c4baffc
TG
289 if (sd_netlink_message_is_error(message)) {
290 r = sd_netlink_message_get_errno(message);
45af44d4
TG
291 if (r < 0)
292 log_warning_errno(r, "rtnl: could not receive link: %m");
293
294 return 0;
295 }
296
1c4baffc 297 r = sd_netlink_message_get_type(message, &type);
f2236469 298 if (r < 0) {
45af44d4 299 log_warning_errno(r, "rtnl: could not get message type: %m");
f2236469 300 return 0;
cdfee943
TG
301 } else if (type != RTM_NEWLINK && type != RTM_DELLINK) {
302 log_warning("rtnl: received unexpected message type when processing link");
303 return 0;
f2236469
TG
304 }
305
505f8da7 306 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
45af44d4 307 if (r < 0) {
cdfee943 308 log_warning_errno(r, "rtnl: could not get ifindex from link: %m");
45af44d4
TG
309 return 0;
310 } else if (ifindex <= 0) {
311 log_warning("rtnl: received link message with invalid ifindex: %d", ifindex);
505f8da7 312 return 0;
4d473d5d
TG
313 } else
314 link_get(m, ifindex, &link);
f579559b 315
1c4baffc 316 r = sd_netlink_message_read_string(message, IFLA_IFNAME, &name);
45af44d4
TG
317 if (r < 0) {
318 log_warning_errno(r, "rtnl: received link message without ifname: %m");
4d473d5d
TG
319 return 0;
320 } else
f2236469 321 netdev_get(m, name, &netdev);
4d473d5d
TG
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) {
17d1f37d 329 log_warning_errno(r, "could not add new link: %m");
4d473d5d
TG
330 return 0;
331 }
332 }
333
334 if (netdev) {
335 /* netdev exists, so make sure the ifindex matches */
505f8da7
TG
336 r = netdev_set_ifindex(netdev, message);
337 if (r < 0) {
17d1f37d 338 log_warning_errno(r, "could not set ifindex on netdev: %m");
505f8da7
TG
339 return 0;
340 }
341 }
e1202047 342
f2236469
TG
343 r = link_update(link, message);
344 if (r < 0)
345 return 0;
4d473d5d
TG
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.");
f2236469 357 }
505f8da7
TG
358
359 return 1;
360}
361
5fae368b
TG
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;
505f8da7
TG
383
384 assert(m);
505f8da7 385
5fae368b
TG
386 fd = systemd_netlink_fd();
387 if (fd < 0)
1c4baffc 388 r = sd_netlink_open(&m->rtnl);
5fae368b 389 else
1c4baffc 390 r = sd_netlink_open_fd(&m->rtnl, fd);
505f8da7
TG
391 if (r < 0)
392 return r;
393
1c4baffc 394 r = sd_netlink_inc_rcvbuf(m->rtnl, RCVBUF_SIZE);
f579559b 395 if (r < 0)
bf5332d2 396 return r;
f579559b 397
1c4baffc 398 r = sd_netlink_attach_event(m->rtnl, m->event, 0);
505f8da7
TG
399 if (r < 0)
400 return r;
f579559b 401
1c4baffc 402 r = sd_netlink_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
5fae368b
TG
403 if (r < 0)
404 return r;
505f8da7 405
1c4baffc 406 r = sd_netlink_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
5fae368b
TG
407 if (r < 0)
408 return r;
45af44d4 409
1c4baffc 410 r = sd_netlink_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
5fae368b
TG
411 if (r < 0)
412 return r;
413
1c4baffc 414 r = sd_netlink_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
5fae368b
TG
415 if (r < 0)
416 return r;
417
418 return 0;
45af44d4 419}
505f8da7 420
5fae368b
TG
421int manager_new(Manager **ret) {
422 _cleanup_manager_free_ Manager *m = NULL;
45af44d4 423 int r;
f579559b 424
5fae368b
TG
425 m = new0(Manager, 1);
426 if (!m)
427 return -ENOMEM;
45af44d4 428
5fae368b
TG
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);
45af44d4
TG
434 if (r < 0)
435 return r;
436
5fae368b
TG
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);
45af44d4
TG
443 if (r < 0)
444 return r;
445
5fae368b
TG
446 r = manager_connect_udev(m);
447 if (r < 0)
448 return r;
45af44d4 449
5fae368b
TG
450 m->netdevs = hashmap_new(&string_hash_ops);
451 if (!m->netdevs)
452 return -ENOMEM;
f579559b 453
5fae368b 454 LIST_HEAD_INIT(m->networks);
f579559b 455
5fae368b
TG
456 r = setup_default_address_pool(m);
457 if (r < 0)
458 return r;
f579559b 459
5fae368b
TG
460 *ret = m;
461 m = NULL;
f579559b 462
f579559b
TG
463 return 0;
464}
465
5fae368b
TG
466void manager_free(Manager *m) {
467 Network *network;
468 NetDev *netdev;
469 Link *link;
470 AddressPool *pool;
f579559b 471
5fae368b
TG
472 if (!m)
473 return;
505f8da7 474
5fae368b 475 free(m->state_file);
505f8da7 476
5fae368b
TG
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);
f579559b 484
5fae368b
TG
485 while ((link = hashmap_first(m->links)))
486 link_unref(link);
487 hashmap_free(m->links);
f579559b 488
5fae368b
TG
489 while ((network = m->networks))
490 network_free(network);
491
dbffab87
TG
492 hashmap_free(m->networks_by_name);
493
5fae368b
TG
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
1c4baffc 501 sd_netlink_unref(m->rtnl);
5fae368b
TG
502
503 free(m);
504}
505
a97dcc12
TG
506static bool manager_check_idle(void *userdata) {
507 Manager *m = userdata;
508 Link *link;
509 Iterator i;
510
511 assert(m);
512
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;
518
519 if (!link->network)
520 continue;
521
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;
529 }
530
531 return true;
532}
533
534int manager_run(Manager *m) {
535 assert(m);
536
f806f64c
TG
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);
a97dcc12
TG
549}
550
5fae368b
TG
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);
f579559b
TG
558 if (r < 0)
559 return r;
560
5fae368b 561 r = network_load(m);
9021bb9f
TG
562 if (r < 0)
563 return r;
564
f579559b
TG
565 return 0;
566}
f882c247 567
5fae368b
TG
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) {
1c4baffc
TG
573 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
574 sd_netlink_message *link;
f882c247
TG
575 int r;
576
5da8149f 577 assert(m);
5fae368b 578 assert(m->rtnl);
5da8149f 579
5fae368b 580 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
f882c247
TG
581 if (r < 0)
582 return r;
583
1c4baffc 584 r = sd_netlink_message_request_dump(req, true);
dd3efc09
TG
585 if (r < 0)
586 return r;
587
1c4baffc 588 r = sd_netlink_call(m->rtnl, req, 0, &reply);
f2236469
TG
589 if (r < 0)
590 return r;
591
1c4baffc 592 for (link = reply; link; link = sd_netlink_message_next(link)) {
5fae368b 593 int k;
2e9f08ea 594
6a24f148
TG
595 m->enumerating = true;
596
5fae368b
TG
597 k = manager_rtnl_process_link(m->rtnl, link, m);
598 if (k < 0)
599 r = k;
6a24f148
TG
600
601 m->enumerating = false;
5fae368b 602 }
2e9f08ea 603
5fae368b 604 return r;
f882c247 605}
3bef724f 606
5fae368b 607int manager_rtnl_enumerate_addresses(Manager *m) {
1c4baffc
TG
608 _cleanup_netlink_message_unref_ sd_netlink_message *req = NULL, *reply = NULL;
609 sd_netlink_message *addr;
1346b1f0
TG
610 int r;
611
5fae368b
TG
612 assert(m);
613 assert(m->rtnl);
bcbca829 614
5fae368b
TG
615 r = sd_rtnl_message_new_addr(m->rtnl, &req, RTM_GETADDR, 0, 0);
616 if (r < 0)
617 return r;
bcbca829 618
1c4baffc 619 r = sd_netlink_message_request_dump(req, true);
1346b1f0
TG
620 if (r < 0)
621 return r;
622
1c4baffc 623 r = sd_netlink_call(m->rtnl, req, 0, &reply);
5fae368b
TG
624 if (r < 0)
625 return r;
626
1c4baffc 627 for (addr = reply; addr; addr = sd_netlink_message_next(addr)) {
5fae368b
TG
628 int k;
629
6a24f148
TG
630 m->enumerating = true;
631
5fae368b
TG
632 k = link_rtnl_process_address(m->rtnl, addr, m);
633 if (k < 0)
634 r = k;
6a24f148
TG
635
636 m->enumerating = false;
5fae368b
TG
637 }
638
639 return r;
1346b1f0
TG
640}
641
c0c743cb
LP
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
8612e936
LP
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
bbf7c048 695int manager_save(Manager *m) {
8612e936 696 _cleanup_set_free_free_ Set *dns = NULL, *ntp = NULL, *domains = NULL;
bbf7c048
TG
697 Link *link;
698 Iterator i;
699 _cleanup_free_ char *temp_path = NULL;
700 _cleanup_fclose_ FILE *f = NULL;
d3df0e39 701 LinkOperationalState operstate = LINK_OPERSTATE_OFF;
e375dcde 702 const char *operstate_str;
bbf7c048
TG
703 int r;
704
705 assert(m);
706 assert(m->state_file);
707
c0c743cb 708 /* We add all NTP and DNS server to a set, to filter out duplicates */
d5099efc 709 dns = set_new(&string_hash_ops);
c0c743cb
LP
710 if (!dns)
711 return -ENOMEM;
712
d5099efc 713 ntp = set_new(&string_hash_ops);
c0c743cb
LP
714 if (!ntp)
715 return -ENOMEM;
716
d5099efc 717 domains = set_new(&string_hash_ops);
8612e936
LP
718 if (!domains)
719 return -ENOMEM;
720
bbf7c048
TG
721 HASHMAP_FOREACH(link, m->links, i) {
722 if (link->flags & IFF_LOOPBACK)
723 continue;
724
e375dcde
TG
725 if (link->operstate > operstate)
726 operstate = link->operstate;
c0c743cb
LP
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
8612e936
LP
740 r = set_put_strdupv(domains, link->network->domains);
741 if (r < 0)
742 return r;
743
c0c743cb
LP
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;
8612e936 756 } else if (r < 0 && r != -ENOENT)
c0c743cb
LP
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;
8612e936
LP
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;
c0c743cb
LP
780 } else if (r != -ENOENT)
781 return r;
782 }
bbf7c048
TG
783 }
784
e375dcde
TG
785 operstate_str = link_operstate_to_string(operstate);
786 assert(operstate_str);
bbf7c048
TG
787
788 r = fopen_temporary(m->state_file, &f, &temp_path);
789 if (r < 0)
c2d6bd61 790 return r;
bbf7c048
TG
791
792 fchmod(fileno(f), 0644);
793
794 fprintf(f,
795 "# This is private data. Do not parse.\n"
e375dcde 796 "OPER_STATE=%s\n", operstate_str);
bbf7c048 797
8612e936
LP
798 print_string_set(f, "DNS=", dns);
799 print_string_set(f, "NTP=", ntp);
800 print_string_set(f, "DOMAINS=", domains);
c0c743cb 801
c2d6bd61
LP
802 r = fflush_and_check(f);
803 if (r < 0)
804 goto fail;
bbf7c048 805
c2d6bd61 806 if (rename(temp_path, m->state_file) < 0) {
bbf7c048 807 r = -errno;
c2d6bd61 808 goto fail;
bbf7c048
TG
809 }
810
e331e246
TG
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
c2d6bd61 818 return 0;
bbf7c048 819
c2d6bd61 820fail:
da927ba9 821 log_error_errno(r, "Failed to save network state to %s: %m", m->state_file);
c2d6bd61
LP
822 unlink(m->state_file);
823 unlink(temp_path);
bbf7c048
TG
824 return r;
825}
11bf3cce 826
0dd25fb9 827int manager_address_pool_acquire(Manager *m, int family, unsigned prefixlen, union in_addr_union *found) {
11bf3cce
LP
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}
cb9fc36a
LP
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}
769d324c
LP
878
879DEFINE_CONFIG_PARSE_ENUM(config_parse_address_family_boolean, address_family_boolean, AddressFamilyBoolean, "Failed to parse option");