chiark / gitweb /
a007b0485f5616ef04f715d9766e209cd6a7ec37
[elogind.git] / src / network / networkd-manager.c
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
22 #include <resolv.h>
23
24 #include "path-util.h"
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "udev-util.h"
28 #include "rtnl-util.h"
29 #include "mkdir.h"
30
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",
37 #endif
38         NULL};
39
40 int manager_new(Manager **ret) {
41         _cleanup_manager_free_ Manager *m = NULL;
42         int r;
43
44         m = new0(Manager, 1);
45         if (!m)
46                 return -ENOMEM;
47
48         r = sd_event_default(&m->event);
49         if (r < 0)
50                 return r;
51
52         sd_event_set_watchdog(m->event, true);
53
54         r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
55         if (r < 0)
56                 return r;
57
58         r = sd_bus_default_system(&m->bus);
59         if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
60                 return r;
61
62         m->udev = udev_new();
63         if (!m->udev)
64                 return -ENOMEM;
65
66         m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
67         if (!m->udev_monitor)
68                 return -ENOMEM;
69
70         m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
71         if (!m->links)
72                 return -ENOMEM;
73
74         m->netdevs = hashmap_new(string_hash_func, string_compare_func);
75         if (!m->netdevs)
76                 return -ENOMEM;
77
78         LIST_HEAD_INIT(m->networks);
79
80         *ret = m;
81         m = NULL;
82
83         return 0;
84 }
85
86 void manager_free(Manager *m) {
87         Network *network;
88         Netdev *netdev;
89         Link *link;
90
91         udev_monitor_unref(m->udev_monitor);
92         udev_unref(m->udev);
93         sd_bus_unref(m->bus);
94         sd_event_source_unref(m->udev_event_source);
95         sd_event_unref(m->event);
96
97         while ((network = m->networks))
98                 network_free(network);
99
100         while ((link = hashmap_first(m->links)))
101                 link_free(link);
102         hashmap_free(m->links);
103
104         while ((netdev = hashmap_first(m->netdevs)))
105                 netdev_free(netdev);
106         hashmap_free(m->netdevs);
107
108         sd_rtnl_unref(m->rtnl);
109
110         free(m);
111 }
112
113 int manager_load_config(Manager *m) {
114         int r;
115
116         /* update timestamp */
117         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
118
119         r = netdev_load(m);
120         if (r < 0)
121                 return r;
122
123         r = network_load(m);
124         if (r < 0)
125                 return r;
126
127         return 0;
128 }
129
130 bool manager_should_reload(Manager *m) {
131         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
132 }
133
134 static int manager_process_link(Manager *m, struct udev_device *device) {
135         Link *link;
136         int r;
137
138         if (streq_ptr(udev_device_get_action(device), "remove")) {
139                 uint64_t ifindex;
140
141                 log_debug("%s: link removed", udev_device_get_sysname(device));
142
143                 ifindex = udev_device_get_ifindex(device);
144                 link = hashmap_get(m->links, &ifindex);
145                 if (!link)
146                         return 0;
147
148                 link_free(link);
149         } else {
150                 r = link_add(m, device, &link);
151                 if (r < 0) {
152                         if (r == -EEXIST)
153                                 log_debug("%s: link already exists, ignoring",
154                                           link->ifname);
155                         else
156                                 log_error("%s: could not handle link: %s",
157                                           udev_device_get_sysname(device),
158                                           strerror(-r));
159                 } else
160                         log_debug("%s: link (with ifindex %" PRIu64") added",
161                                   link->ifname, link->ifindex);
162         }
163
164         return 0;
165 }
166
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;
170         int r;
171
172         assert(m);
173
174         e = udev_enumerate_new(m->udev);
175         if (!e)
176                 return -ENOMEM;
177
178         r = udev_enumerate_add_match_subsystem(e, "net");
179         if (r < 0)
180                 return r;
181
182         r = udev_enumerate_add_match_is_initialized(e);
183         if (r < 0)
184                 return r;
185
186         r = udev_enumerate_scan_devices(e);
187         if (r < 0)
188                 return r;
189
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;
193                 int k;
194
195                 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
196                 if (!d)
197                         return -ENOMEM;
198
199                 k = manager_process_link(m, d);
200                 if (k < 0)
201                         r = k;
202         }
203
204         return r;
205 }
206
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;
211
212         device = udev_monitor_receive_device(monitor);
213         if (!device)
214                 return -ENOMEM;
215
216         manager_process_link(m, device);
217         return 0;
218 }
219
220 int manager_udev_listen(Manager *m) {
221         int r;
222
223         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
224         if (r < 0) {
225                 log_error("Could not add udev monitor filter: %s", strerror(-r));
226                 return r;
227         }
228
229         r = udev_monitor_enable_receiving(m->udev_monitor);
230         if (r < 0) {
231                 log_error("Could not enable udev monitor");
232                 return r;
233         }
234
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);
239         if (r < 0)
240                 return r;
241
242         return 0;
243 }
244
245 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
246         Manager *m = userdata;
247         Link *link;
248         const char *name;
249         uint64_t ifindex_64;
250         int r, ifindex;
251
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");
255                 return 0;
256         }
257
258         r = rtnl_message_link_get_ifname(message, &name);
259         if (r < 0)
260                 log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME");
261         else {
262                 Netdev *netdev;
263
264                 r = netdev_get(m, name, &netdev);
265                 if (r >= 0) {
266                         r = netdev_set_ifindex(netdev, ifindex);
267                         if (r < 0)
268                                 log_debug("could not set ifindex of netdev '%s' to %d: %s",
269                                           name, ifindex, strerror(-r));
270                 }
271         }
272
273         ifindex_64 = ifindex;
274         link = hashmap_get(m->links, &ifindex_64);
275         if (!link) {
276                 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
277                 return 0;
278         }
279
280         /* only track the status of links we want to manage */
281         if (link->network) {
282                 r = link_update(link, message);
283                 if (r < 0)
284                         return 0;
285         } else
286                 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
287
288         return 1;
289 }
290
291 int manager_rtnl_listen(Manager *m) {
292         int r;
293
294         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
295         if (r < 0)
296                 return r;
297
298         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
299         if (r < 0)
300                 return r;
301
302         return 0;
303 }
304
305 int manager_bus_listen(Manager *m) {
306         int r;
307
308         assert(m->event);
309
310         if (!m->bus) /* TODO: drop when we can rely on kdbus */
311                 return 0;
312
313         r = sd_bus_attach_event(m->bus, m->event, 0);
314         if (r < 0)
315                 return r;
316
317         return 0;
318 }
319
320 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
321         char buf[INET6_ADDRSTRLEN];
322         const char *address;
323
324         address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
325         if (!address) {
326                 log_warning("Invalid DNS address. Ignoring.");
327                 return;
328         }
329
330         if (*count == MAXNS)
331                 fputs("# Too many DNS servers configured, the following entries "
332                       "will be ignored\n", f);
333
334         fprintf(f, "nameserver %s\n", address);
335
336         (*count) ++;
337 }
338
339 int manager_update_resolv_conf(Manager *m) {
340         _cleanup_free_ char *temp_path = NULL;
341         _cleanup_fclose_ FILE *f = NULL;
342         Link *link;
343         Iterator i;
344         unsigned count = 0;
345         const char *domainname = NULL;
346         int r;
347
348         assert(m);
349
350         r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
351         if (r < 0)
352                 return r;
353
354         r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
355         if (r < 0)
356                 return r;
357
358         fchmod(fileno(f), 0644);
359
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);
365
366         HASHMAP_FOREACH(link, m->links, i) {
367                 if (link->dhcp) {
368                         struct in_addr *nameservers;
369                         size_t nameservers_size;
370
371                         if (link->network->dhcp_dns) {
372                                 r = sd_dhcp_client_get_dns(link->dhcp, &nameservers, &nameservers_size);
373                                 if (r >= 0) {
374                                         unsigned j;
375
376                                         for (j = 0; j < nameservers_size; j++)
377                                                 append_dns(f, &nameservers[j], AF_INET, &count);
378                                 }
379                         }
380
381                         if (link->network->dhcp_domainname && !domainname) {
382                                 r = sd_dhcp_client_get_domainname(link->dhcp, &domainname);
383                                 if (r >= 0)
384                                        fprintf(f, "domain %s\n", domainname);
385                         }
386                 }
387         }
388
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);
393
394         fflush(f);
395
396         if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
397                 r = -errno;
398                 unlink("/run/systemd/network/resolv.conf");
399                 unlink(temp_path);
400                 return r;
401         }
402
403         return 0;
404 }