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