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