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