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"
30 const char* const network_dirs[] = {
31 "/etc/systemd/network",
32 "/run/systemd/network",
33 "/usr/lib/systemd/network",
34 #ifdef HAVE_SPLIT_USER
35 "/lib/systemd/network",
39 int manager_new(Manager **ret) {
40 _cleanup_manager_free_ Manager *m = NULL;
47 r = sd_event_default(&m->event);
51 sd_event_set_watchdog(m->event, true);
53 r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
61 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
65 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
69 m->bridges = hashmap_new(string_hash_func, string_compare_func);
73 LIST_HEAD_INIT(m->networks);
81 void manager_free(Manager *m) {
86 udev_monitor_unref(m->udev_monitor);
88 sd_event_source_unref(m->udev_event_source);
89 sd_event_unref(m->event);
91 while ((network = m->networks))
92 network_free(network);
94 while ((link = hashmap_first(m->links)))
96 hashmap_free(m->links);
98 while ((bridge = hashmap_first(m->bridges)))
100 hashmap_free(m->bridges);
102 sd_rtnl_unref(m->rtnl);
107 int manager_load_config(Manager *m) {
110 /* update timestamp */
111 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
124 bool manager_should_reload(Manager *m) {
125 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
128 static int manager_process_link(Manager *m, struct udev_device *device) {
132 if (streq_ptr(udev_device_get_action(device), "remove")) {
135 log_debug("%s: link removed", udev_device_get_sysname(device));
137 ifindex = udev_device_get_ifindex(device);
138 link = hashmap_get(m->links, &ifindex);
144 r = link_add(m, device, &link);
147 log_debug("%s: link already exists, ignoring",
150 log_error("%s: could not handle link: %s",
151 udev_device_get_sysname(device),
154 log_debug("%s: link (with ifindex %" PRIu64") added",
155 link->ifname, link->ifindex);
161 int manager_udev_enumerate_links(Manager *m) {
162 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
163 struct udev_list_entry *item = NULL, *first = NULL;
168 e = udev_enumerate_new(m->udev);
172 r = udev_enumerate_add_match_subsystem(e, "net");
176 r = udev_enumerate_add_match_is_initialized(e);
180 r = udev_enumerate_scan_devices(e);
184 first = udev_enumerate_get_list_entry(e);
185 udev_list_entry_foreach(item, first) {
186 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
189 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
193 k = manager_process_link(m, d);
201 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
202 Manager *m = userdata;
203 struct udev_monitor *monitor = m->udev_monitor;
204 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
206 device = udev_monitor_receive_device(monitor);
210 manager_process_link(m, device);
214 int manager_udev_listen(Manager *m) {
217 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
219 log_error("Could not add udev monitor filter: %s", strerror(-r));
223 r = udev_monitor_enable_receiving(m->udev_monitor);
225 log_error("Could not enable udev monitor");
229 r = sd_event_add_io(m->event,
230 udev_monitor_get_fd(m->udev_monitor),
231 EPOLLIN, manager_dispatch_link_udev,
232 m, &m->udev_event_source);
239 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
240 Manager *m = userdata;
245 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
247 log_debug("received RTM_NEWLINK message without valid ifindex");
251 ifindex_64 = ifindex;
252 link = hashmap_get(m->links, &ifindex_64);
254 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
258 /* only track the status of links we want to manage */
260 r = link_update(link, message);
264 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
269 int manager_rtnl_listen(Manager *m) {
272 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
276 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
283 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
284 char buf[INET6_ADDRSTRLEN];
287 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
289 log_warning("Invalid DNS address. Ignoring.");
294 fputs("# Too many dynamic name servers configured, the "
295 "following entries will be ignored\n", f);
297 fprintf(f, "nameserver %s\n", address);
302 int manager_update_resolv_conf(Manager *m) {
303 _cleanup_free_ char *temp_path = NULL;
304 _cleanup_fclose_ FILE *f = NULL;
312 r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
316 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
320 fchmod(fileno(f), 0644);
322 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n", f);
324 HASHMAP_FOREACH(link, m->links, i) {
326 struct in_addr **nameservers;
328 r = sd_dhcp_client_get_dns(link->dhcp, &nameservers);
332 for (j = 0; nameservers[j]; j++)
333 append_dns(f, nameservers[j], AF_INET, &count);
338 HASHMAP_FOREACH(link, m->links, i)
339 if (link->network && link->network->dns)
340 append_dns(f, &link->network->dns->in_addr.in,
341 link->network->dns->family, &count);
345 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
347 unlink("/run/systemd/network/resolv.conf");