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"
31 const char* const network_dirs[] = {
32 "/etc/systemd/network",
33 "/run/systemd/network",
34 "/usr/lib/systemd/network",
35 #ifdef HAVE_SPLIT_USER
36 "/lib/systemd/network",
40 int manager_new(Manager **ret) {
41 _cleanup_manager_free_ Manager *m = NULL;
48 r = sd_event_default(&m->event);
52 sd_event_set_watchdog(m->event, true);
54 r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
58 r = sd_bus_default_system(&m->bus);
59 if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
66 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
70 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
74 m->netdevs = hashmap_new(string_hash_func, string_compare_func);
78 LIST_HEAD_INIT(m->networks);
86 void manager_free(Manager *m) {
91 udev_monitor_unref(m->udev_monitor);
94 sd_event_source_unref(m->udev_event_source);
95 sd_event_unref(m->event);
97 while ((network = m->networks))
98 network_free(network);
100 while ((link = hashmap_first(m->links)))
102 hashmap_free(m->links);
104 while ((netdev = hashmap_first(m->netdevs)))
106 hashmap_free(m->netdevs);
108 sd_rtnl_unref(m->rtnl);
113 int manager_load_config(Manager *m) {
116 /* update timestamp */
117 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
130 bool manager_should_reload(Manager *m) {
131 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
134 static int manager_process_link(Manager *m, struct udev_device *device) {
138 if (streq_ptr(udev_device_get_action(device), "remove")) {
141 log_debug("%s: link removed", udev_device_get_sysname(device));
143 ifindex = udev_device_get_ifindex(device);
144 link = hashmap_get(m->links, &ifindex);
150 r = link_add(m, device, &link);
153 log_debug("%s: link already exists, ignoring",
156 log_error("%s: could not handle link: %s",
157 udev_device_get_sysname(device),
160 log_debug("%s: link (with ifindex %" PRIu64") added",
161 link->ifname, link->ifindex);
167 int manager_udev_enumerate_links(Manager *m) {
168 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
169 struct udev_list_entry *item = NULL, *first = NULL;
174 e = udev_enumerate_new(m->udev);
178 r = udev_enumerate_add_match_subsystem(e, "net");
182 r = udev_enumerate_add_match_is_initialized(e);
186 r = udev_enumerate_scan_devices(e);
190 first = udev_enumerate_get_list_entry(e);
191 udev_list_entry_foreach(item, first) {
192 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
195 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
199 k = manager_process_link(m, d);
207 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
208 Manager *m = userdata;
209 struct udev_monitor *monitor = m->udev_monitor;
210 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
212 device = udev_monitor_receive_device(monitor);
216 manager_process_link(m, device);
220 int manager_udev_listen(Manager *m) {
223 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
225 log_error("Could not add udev monitor filter: %s", strerror(-r));
229 r = udev_monitor_enable_receiving(m->udev_monitor);
231 log_error("Could not enable udev monitor");
235 r = sd_event_add_io(m->event,
236 udev_monitor_get_fd(m->udev_monitor),
237 EPOLLIN, manager_dispatch_link_udev,
238 m, &m->udev_event_source);
245 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
246 Manager *m = userdata;
252 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
253 if (r < 0 || ifindex <= 0) {
254 log_debug("received RTM_NEWLINK message without valid ifindex");
258 r = rtnl_message_link_get_ifname(message, &name);
260 log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME");
264 r = netdev_get(m, name, &netdev);
266 r = netdev_set_ifindex(netdev, ifindex);
268 log_debug("could not set ifindex of netdev '%s' to %d: %s",
269 name, ifindex, strerror(-r));
273 ifindex_64 = ifindex;
274 link = hashmap_get(m->links, &ifindex_64);
276 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
280 /* only track the status of links we want to manage */
282 r = link_update(link, message);
286 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
291 int manager_rtnl_listen(Manager *m) {
294 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
298 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
305 int manager_bus_listen(Manager *m) {
310 if (!m->bus) /* TODO: drop when we can rely on kdbus */
313 r = sd_bus_attach_event(m->bus, m->event, 0);
320 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
321 char buf[INET6_ADDRSTRLEN];
324 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
326 log_warning("Invalid DNS address. Ignoring.");
331 fputs("# Too many DNS servers configured, the following entries "
332 "will be ignored\n", f);
334 fprintf(f, "nameserver %s\n", address);
339 int manager_update_resolv_conf(Manager *m) {
340 _cleanup_free_ char *temp_path = NULL;
341 _cleanup_fclose_ FILE *f = NULL;
345 const char *domainname = NULL;
350 r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
354 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
358 fchmod(fileno(f), 0644);
360 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
361 "# Third party programs must not access this file directly, but\n"
362 "# only through the symlink at /etc/resolv.conf. To manage\n"
363 "# resolv.conf(5) in a different way, replace the symlink by a\n"
364 "# static file or a different symlink.\n\n", f);
366 HASHMAP_FOREACH(link, m->links, i) {
367 if (link->dhcp_lease) {
368 struct in_addr *nameservers;
369 size_t nameservers_size;
371 if (link->network->dhcp_dns) {
372 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
376 for (j = 0; j < nameservers_size; j++)
377 append_dns(f, &nameservers[j], AF_INET, &count);
381 if (link->network->dhcp_domainname && !domainname) {
382 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
384 fprintf(f, "domain %s\n", domainname);
389 HASHMAP_FOREACH(link, m->links, i)
390 if (link->network && link->network->dns)
391 append_dns(f, &link->network->dns->in_addr.in,
392 link->network->dns->family, &count);
396 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
398 unlink("/run/systemd/network/resolv.conf");