1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
24 #include "path-util.h"
26 #include "libudev-private.h"
27 #include "udev-util.h"
28 #include "rtnl-util.h"
32 const char* const network_dirs[] = {
33 "/etc/systemd/network",
34 "/run/systemd/network",
35 "/usr/lib/systemd/network",
37 "/lib/systemd/network",
41 static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
42 Manager *m = userdata;
46 log_received_signal(LOG_INFO, si);
48 sd_event_exit(m->event, 0);
52 static int setup_signals(Manager *m) {
58 assert_se(sigemptyset(&mask) == 0);
59 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
60 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
62 r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
66 r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
73 int manager_new(Manager **ret) {
74 _cleanup_manager_free_ Manager *m = NULL;
81 r = sd_event_default(&m->event);
85 sd_event_set_watchdog(m->event, true);
87 r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
91 r = sd_bus_default_system(&m->bus);
92 if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
103 /* udev does not initialize devices inside containers,
104 * so we rely on them being already initialized before
105 * entering the container */
106 if (detect_container(NULL) > 0) {
107 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "kernel");
108 if (!m->udev_monitor)
111 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
112 if (!m->udev_monitor)
116 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
120 m->netdevs = hashmap_new(string_hash_func, string_compare_func);
124 LIST_HEAD_INIT(m->networks);
132 void manager_free(Manager *m) {
140 udev_monitor_unref(m->udev_monitor);
142 sd_bus_unref(m->bus);
143 sd_event_source_unref(m->udev_event_source);
144 sd_event_source_unref(m->sigterm_event_source);
145 sd_event_source_unref(m->sigint_event_source);
146 sd_event_unref(m->event);
148 while ((network = m->networks))
149 network_free(network);
151 while ((link = hashmap_first(m->links)))
153 hashmap_free(m->links);
155 while ((netdev = hashmap_first(m->netdevs)))
157 hashmap_free(m->netdevs);
159 sd_rtnl_unref(m->rtnl);
164 int manager_load_config(Manager *m) {
167 /* update timestamp */
168 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
181 bool manager_should_reload(Manager *m) {
182 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
185 static int manager_process_link(Manager *m, struct udev_device *device) {
192 link_get(m, udev_device_get_ifindex(device), &link);
194 if (streq_ptr(udev_device_get_action(device), "remove")) {
195 log_debug("%s: link removed", udev_device_get_sysname(device));
201 log_debug("%s: link already exists, ignoring",
206 r = link_add(m, device, &link);
208 log_error("%s: could not handle link: %s",
209 udev_device_get_sysname(device),
212 log_debug("%s: link (with ifindex %" PRIu64") added",
213 link->ifname, link->ifindex);
219 int manager_udev_enumerate_links(Manager *m) {
220 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
221 struct udev_list_entry *item = NULL, *first = NULL;
226 e = udev_enumerate_new(m->udev);
230 r = udev_enumerate_add_match_subsystem(e, "net");
234 /* udev does not initialize devices inside containers,
235 * so we rely on them being already initialized before
236 * entering the container */
237 if (detect_container(NULL) <= 0) {
238 r = udev_enumerate_add_match_is_initialized(e);
243 r = udev_enumerate_scan_devices(e);
247 first = udev_enumerate_get_list_entry(e);
248 udev_list_entry_foreach(item, first) {
249 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
252 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
256 k = manager_process_link(m, d);
264 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
265 Manager *m = userdata;
266 struct udev_monitor *monitor = m->udev_monitor;
267 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
269 device = udev_monitor_receive_device(monitor);
273 manager_process_link(m, device);
277 int manager_udev_listen(Manager *m) {
280 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
282 log_error("Could not add udev monitor filter: %s", strerror(-r));
286 r = udev_monitor_enable_receiving(m->udev_monitor);
288 log_error("Could not enable udev monitor");
292 r = sd_event_add_io(m->event,
293 &m->udev_event_source,
294 udev_monitor_get_fd(m->udev_monitor),
295 EPOLLIN, manager_dispatch_link_udev,
303 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
304 Manager *m = userdata;
313 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
314 if (r < 0 || ifindex <= 0) {
315 log_warning("received RTM_NEWLINK message without valid ifindex");
319 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
321 log_warning("received RTM_NEWLINK message without valid ifname");
325 r = netdev_get(m, name, &netdev);
327 r = netdev_set_ifindex(netdev, message);
329 log_debug("could not set ifindex of netdev '%s' to %d: %s",
330 name, ifindex, strerror(-r));
334 r = link_get(m, ifindex, &link);
336 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
340 /* only track the status of links we want to manage */
342 r = link_update(link, message);
346 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
351 int manager_rtnl_listen(Manager *m) {
354 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
358 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
365 int manager_bus_listen(Manager *m) {
370 if (!m->bus) /* TODO: drop when we can rely on kdbus */
373 r = sd_bus_attach_event(m->bus, m->event, 0);
380 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
381 char buf[INET6_ADDRSTRLEN];
384 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
386 log_warning("Invalid DNS address. Ignoring.");
391 fputs("# Too many DNS servers configured, the following entries "
392 "will be ignored\n", f);
394 fprintf(f, "nameserver %s\n", address);
399 int manager_update_resolv_conf(Manager *m) {
400 _cleanup_free_ char *temp_path = NULL;
401 _cleanup_fclose_ FILE *f = NULL;
405 const char *domainname = NULL;
410 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
414 fchmod(fileno(f), 0644);
416 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
417 "# Third party programs must not access this file directly, but\n"
418 "# only through the symlink at /etc/resolv.conf. To manage\n"
419 "# resolv.conf(5) in a different way, replace the symlink by a\n"
420 "# static file or a different symlink.\n\n", f);
422 HASHMAP_FOREACH(link, m->links, i) {
423 if (link->dhcp_lease) {
424 struct in_addr *nameservers;
425 size_t nameservers_size;
427 if (link->network->dhcp_dns) {
428 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
432 for (j = 0; j < nameservers_size; j++)
433 append_dns(f, &nameservers[j], AF_INET, &count);
437 if (link->network->dhcp_domainname && !domainname) {
438 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
440 fprintf(f, "domain %s\n", domainname);
445 HASHMAP_FOREACH(link, m->links, i) {
446 if (link->network && link->network->dns) {
450 SET_FOREACH(address, link->network->dns, j) {
451 append_dns(f, &address->in_addr.in,
452 address->family, &count);
459 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
461 unlink("/run/systemd/network/resolv.conf");