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