chiark / gitweb /
28de7919daebf83f8211d1bf09867d5d391564bf
[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 #include "virt.h"
31
32 #include "sd-rtnl.h"
33
34 const char* const network_dirs[] = {
35         "/etc/systemd/network",
36         "/run/systemd/network",
37         "/usr/lib/systemd/network",
38 #ifdef HAVE_SPLIT_USR
39         "/lib/systemd/network",
40 #endif
41         NULL};
42
43 static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
44         Manager *m = userdata;
45
46         assert(m);
47
48         log_received_signal(LOG_INFO, si);
49
50         sd_event_exit(m->event, 0);
51         return 0;
52 }
53
54 static int setup_signals(Manager *m) {
55         sigset_t mask;
56         int r;
57
58         assert(m);
59
60         assert_se(sigemptyset(&mask) == 0);
61         sigset_add_many(&mask, SIGINT, SIGTERM, -1);
62         assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
63
64         r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
65         if (r < 0)
66                 return r;
67
68         r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
69         if (r < 0)
70                 return r;
71
72         return 0;
73 }
74
75 int manager_new(Manager **ret) {
76         _cleanup_manager_free_ Manager *m = NULL;
77         int r;
78
79         m = new0(Manager, 1);
80         if (!m)
81                 return -ENOMEM;
82
83         r = sd_event_default(&m->event);
84         if (r < 0)
85                 return r;
86
87         sd_event_set_watchdog(m->event, true);
88
89         r = sd_rtnl_open(&m->rtnl, RTMGRP_LINK | RTMGRP_IPV4_IFADDR);
90         if (r < 0)
91                 return r;
92
93         r = sd_bus_default_system(&m->bus);
94         if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
95                 return r;
96
97         r = setup_signals(m);
98         if (r < 0)
99                 return r;
100
101         /* udev does not initialize devices inside containers,
102          * so we rely on them being already initialized before
103          * entering the container */
104         if (detect_container(NULL) <= 0) {
105                 m->udev = udev_new();
106                 if (!m->udev)
107                         return -ENOMEM;
108
109                 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
110                 if (!m->udev_monitor)
111                         return -ENOMEM;
112         }
113
114         m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
115         if (!m->links)
116                 return -ENOMEM;
117
118         m->netdevs = hashmap_new(string_hash_func, string_compare_func);
119         if (!m->netdevs)
120                 return -ENOMEM;
121
122         LIST_HEAD_INIT(m->networks);
123
124         *ret = m;
125         m = NULL;
126
127         return 0;
128 }
129
130 void manager_free(Manager *m) {
131         Network *network;
132         NetDev *netdev;
133         Link *link;
134
135         if (!m)
136                 return;
137
138         udev_monitor_unref(m->udev_monitor);
139         udev_unref(m->udev);
140         sd_bus_unref(m->bus);
141         sd_event_source_unref(m->udev_event_source);
142         sd_event_source_unref(m->sigterm_event_source);
143         sd_event_source_unref(m->sigint_event_source);
144         sd_event_unref(m->event);
145
146         while ((link = hashmap_first(m->links)))
147                 link_free(link);
148         hashmap_free(m->links);
149
150         while ((network = m->networks))
151                 network_free(network);
152
153         while ((netdev = hashmap_first(m->netdevs)))
154                 netdev_free(netdev);
155         hashmap_free(m->netdevs);
156
157         sd_rtnl_unref(m->rtnl);
158
159         free(m);
160 }
161
162 int manager_load_config(Manager *m) {
163         int r;
164
165         /* update timestamp */
166         paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
167
168         r = netdev_load(m);
169         if (r < 0)
170                 return r;
171
172         r = network_load(m);
173         if (r < 0)
174                 return r;
175
176         return 0;
177 }
178
179 bool manager_should_reload(Manager *m) {
180         return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
181 }
182
183 static int manager_udev_process_link(Manager *m, struct udev_device *device) {
184         Link *link = NULL;
185         int r, ifindex;
186
187         assert(m);
188         assert(device);
189
190         if (!streq_ptr(udev_device_get_action(device), "add"))
191                 return 0;
192
193         ifindex = udev_device_get_ifindex(device);
194         if (ifindex <= 0) {
195                 log_debug("ignoring udev ADD event for device with invalid ifindex");
196                 return 0;
197         }
198
199         r = link_get(m, ifindex, &link);
200         if (r == -ENODEV)
201                 return 0;
202         else if (r < 0)
203                 return r;
204
205         r = link_initialized(link, device);
206         if (r < 0)
207                 return r;
208
209         return 0;
210 }
211
212 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
213         Manager *m = userdata;
214         Link *link = NULL;
215         char *name;
216         int r, ifindex;
217
218         assert(rtnl);
219         assert(message);
220         assert(m);
221
222         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
223         if (r < 0 || ifindex <= 0) {
224                 log_warning("rtnl: received link message without valid ifindex");
225                 return 0;
226         }
227
228         link_get(m, ifindex, &link);
229         if (!link) {
230                 /* link is new, so add it */
231                 r = link_add(m, message, &link);
232                 if (r < 0) {
233                         log_debug("could not add new link");
234                         return 0;
235                 }
236         }
237
238         r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
239         if (r < 0)
240                 log_warning("rtnl: received link message without valid ifname");
241         else {
242                 NetDev *netdev;
243
244                 r = netdev_get(m, name, &netdev);
245                 if (r >= 0) {
246                         r = netdev_set_ifindex(netdev, message);
247                         if (r < 0) {
248                                 log_debug("could not set ifindex on netdev");
249                                 return 0;
250                         }
251                 }
252         }
253
254         r = link_update(link, message);
255         if (r < 0)
256                 return 0;
257
258         return 1;
259 }
260
261 int manager_rtnl_enumerate_links(Manager *m) {
262         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
263         sd_rtnl_message *link;
264         int r, k;
265
266         assert(m);
267         assert(m->rtnl);
268
269         r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
270         if (r < 0)
271                 return r;
272
273         r = sd_rtnl_message_request_dump(req, true);
274         if (r < 0)
275                 return r;
276
277         r = sd_rtnl_call(m->rtnl, req, 0, &reply);
278         if (r < 0)
279                 return r;
280
281         for (link = reply; link; link = sd_rtnl_message_next(link)) {
282                 uint16_t type;
283
284                 k = sd_rtnl_message_get_type(link, &type);
285                 if (k < 0)
286                         return k;
287
288                 if (type != RTM_NEWLINK)
289                         continue;
290
291                 k = manager_rtnl_process_link(m->rtnl, link, m);
292                 if (k < 0)
293                         r = k;
294         }
295
296         return r;
297 }
298
299 static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
300         Manager *m = userdata;
301         struct udev_monitor *monitor = m->udev_monitor;
302         _cleanup_udev_device_unref_ struct udev_device *device = NULL;
303
304         device = udev_monitor_receive_device(monitor);
305         if (!device)
306                 return -ENOMEM;
307
308         manager_udev_process_link(m, device);
309         return 0;
310 }
311
312 int manager_udev_listen(Manager *m) {
313         int r;
314
315         if (detect_container(NULL) > 0)
316                 return 0;
317
318         assert(m->udev_monitor);
319
320         r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
321         if (r < 0) {
322                 log_error("Could not add udev monitor filter: %s", strerror(-r));
323                 return r;
324         }
325
326         r = udev_monitor_enable_receiving(m->udev_monitor);
327         if (r < 0) {
328                 log_error("Could not enable udev monitor");
329                 return r;
330         }
331
332         r = sd_event_add_io(m->event,
333                         &m->udev_event_source,
334                         udev_monitor_get_fd(m->udev_monitor),
335                         EPOLLIN, manager_dispatch_link_udev,
336                         m);
337         if (r < 0)
338                 return r;
339
340         return 0;
341 }
342
343 int manager_rtnl_listen(Manager *m) {
344         int r;
345
346         r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
347         if (r < 0)
348                 return r;
349
350         r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
351         if (r < 0)
352                 return r;
353
354         return 0;
355 }
356
357 int manager_bus_listen(Manager *m) {
358         int r;
359
360         assert(m->event);
361
362         if (!m->bus) /* TODO: drop when we can rely on kdbus */
363                 return 0;
364
365         r = sd_bus_attach_event(m->bus, m->event, 0);
366         if (r < 0)
367                 return r;
368
369         return 0;
370 }
371
372 static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
373         char buf[INET6_ADDRSTRLEN];
374         const char *address;
375
376         address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
377         if (!address) {
378                 log_warning("Invalid DNS address. Ignoring.");
379                 return;
380         }
381
382         if (*count == MAXNS)
383                 fputs("# Too many DNS servers configured, the following entries "
384                       "will be ignored\n", f);
385
386         fprintf(f, "nameserver %s\n", address);
387
388         (*count) ++;
389 }
390
391 int manager_update_resolv_conf(Manager *m) {
392         _cleanup_free_ char *temp_path = NULL;
393         _cleanup_fclose_ FILE *f = NULL;
394         Link *link;
395         Iterator i;
396         unsigned count = 0;
397         const char *domainname = NULL;
398         int r;
399
400         assert(m);
401
402         r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
403         if (r < 0)
404                 return r;
405
406         fchmod(fileno(f), 0644);
407
408         fputs("# This file is managed by systemd-networkd(8). Do not edit.\n#\n"
409               "# Third party programs must not access this file directly, but\n"
410               "# only through the symlink at /etc/resolv.conf. To manage\n"
411               "# resolv.conf(5) in a different way, replace the symlink by a\n"
412               "# static file or a different symlink.\n\n", f);
413
414         HASHMAP_FOREACH(link, m->links, i) {
415                 if (link->dhcp_lease) {
416                         struct in_addr *nameservers;
417                         size_t nameservers_size;
418
419                         if (link->network->dhcp_dns) {
420                                 r = sd_dhcp_lease_get_dns(link->dhcp_lease, &nameservers, &nameservers_size);
421                                 if (r >= 0) {
422                                         unsigned j;
423
424                                         for (j = 0; j < nameservers_size; j++)
425                                                 append_dns(f, &nameservers[j], AF_INET, &count);
426                                 }
427                         }
428
429                         if (link->network->dhcp_domainname && !domainname) {
430                                 r = sd_dhcp_lease_get_domainname(link->dhcp_lease, &domainname);
431                                 if (r >= 0)
432                                        fprintf(f, "domain %s\n", domainname);
433                         }
434                 }
435         }
436
437         HASHMAP_FOREACH(link, m->links, i) {
438                 if (link->network && link->network->dns) {
439                         Address *address;
440                         Iterator j;
441
442                         SET_FOREACH(address, link->network->dns, j) {
443                                 append_dns(f, &address->in_addr.in,
444                                            address->family, &count);
445                         }
446                 }
447         }
448
449         fflush(f);
450
451         if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
452                 r = -errno;
453                 unlink("/run/systemd/network/resolv.conf");
454                 unlink(temp_path);
455                 return r;
456         }
457
458         return 0;
459 }