]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
networkd: add a number of calls to manipulate in_addr_union structs
[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
091a364c 22#include <sys/socket.h>
bbf7c048 23#include <linux/if.h>
3bef724f 24
2dcf7ec6 25#include "conf-parser.h"
f579559b
TG
26#include "path-util.h"
27#include "networkd.h"
e16cb2e4 28#include "network-internal.h"
f579559b 29#include "libudev-private.h"
7b77ed8c 30#include "udev-util.h"
50add290 31#include "rtnl-util.h"
3bef724f 32#include "mkdir.h"
60ad0c85 33#include "virt.h"
f579559b 34
505f8da7
TG
35#include "sd-rtnl.h"
36
2ad8416d
ZJS
37const char* const network_dirs[] = {
38 "/etc/systemd/network",
39 "/run/systemd/network",
40 "/usr/lib/systemd/network",
eed0eee8 41#ifdef HAVE_SPLIT_USR
2ad8416d
ZJS
42 "/lib/systemd/network",
43#endif
44 NULL};
45
0c2f9b84
TG
46static int dispatch_sigterm(sd_event_source *es, const struct signalfd_siginfo *si, void *userdata) {
47 Manager *m = userdata;
48
49 assert(m);
50
51 log_received_signal(LOG_INFO, si);
52
53 sd_event_exit(m->event, 0);
54 return 0;
55}
56
57static int setup_signals(Manager *m) {
58 sigset_t mask;
59 int r;
60
61 assert(m);
62
63 assert_se(sigemptyset(&mask) == 0);
64 sigset_add_many(&mask, SIGINT, SIGTERM, -1);
65 assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
66
67 r = sd_event_add_signal(m->event, &m->sigterm_event_source, SIGTERM, dispatch_sigterm, m);
68 if (r < 0)
69 return r;
70
71 r = sd_event_add_signal(m->event, &m->sigint_event_source, SIGINT, dispatch_sigterm, m);
72 if (r < 0)
73 return r;
74
75 return 0;
76}
77
f579559b
TG
78int manager_new(Manager **ret) {
79 _cleanup_manager_free_ Manager *m = NULL;
80 int r;
81
82 m = new0(Manager, 1);
83 if (!m)
84 return -ENOMEM;
85
85b5673b 86 m->state_file = strdup("/run/systemd/netif/state");
bbf7c048
TG
87 if (!m->state_file)
88 return -ENOMEM;
89
afc6adb5 90 r = sd_event_default(&m->event);
f579559b
TG
91 if (r < 0)
92 return r;
93
cde93897
LP
94 sd_event_set_watchdog(m->event, true);
95
897e184c
TG
96 r = sd_rtnl_open(&m->rtnl, 3, RTNLGRP_LINK, RTNLGRP_IPV4_IFADDR,
97 RTNLGRP_IPV6_IFADDR);
f579559b
TG
98 if (r < 0)
99 return r;
100
1346b1f0 101 r = sd_bus_default_system(&m->bus);
bcbca829 102 if (r < 0 && r != -ENOENT) /* TODO: drop when we can rely on kdbus */
1346b1f0
TG
103 return r;
104
0c2f9b84
TG
105 r = setup_signals(m);
106 if (r < 0)
107 return r;
108
60ad0c85
TG
109 /* udev does not initialize devices inside containers,
110 * so we rely on them being already initialized before
111 * entering the container */
505f8da7
TG
112 if (detect_container(NULL) <= 0) {
113 m->udev = udev_new();
114 if (!m->udev)
60ad0c85 115 return -ENOMEM;
505f8da7 116
60ad0c85
TG
117 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
118 if (!m->udev_monitor)
119 return -ENOMEM;
120 }
f579559b
TG
121
122 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
123 if (!m->links)
124 return -ENOMEM;
125
52433f6b
TG
126 m->netdevs = hashmap_new(string_hash_func, string_compare_func);
127 if (!m->netdevs)
02b59d57
TG
128 return -ENOMEM;
129
f579559b
TG
130 LIST_HEAD_INIT(m->networks);
131
f579559b
TG
132 *ret = m;
133 m = NULL;
134
135 return 0;
136}
137
138void manager_free(Manager *m) {
0617ffab 139 Network *network;
1a436809 140 NetDev *netdev;
0617ffab
TG
141 Link *link;
142
624b5a63
TG
143 if (!m)
144 return;
145
bbf7c048
TG
146 free(m->state_file);
147
f579559b
TG
148 udev_monitor_unref(m->udev_monitor);
149 udev_unref(m->udev);
1346b1f0 150 sd_bus_unref(m->bus);
f579559b 151 sd_event_source_unref(m->udev_event_source);
0c2f9b84
TG
152 sd_event_source_unref(m->sigterm_event_source);
153 sd_event_source_unref(m->sigint_event_source);
f579559b 154 sd_event_unref(m->event);
0617ffab 155
0617ffab 156 while ((link = hashmap_first(m->links)))
14b746f7 157 link_unref(link);
f579559b 158 hashmap_free(m->links);
0617ffab 159
2292547a
TG
160 while ((network = m->networks))
161 network_free(network);
162
52433f6b 163 while ((netdev = hashmap_first(m->netdevs)))
14b746f7 164 netdev_unref(netdev);
52433f6b 165 hashmap_free(m->netdevs);
02b59d57 166
f579559b
TG
167 sd_rtnl_unref(m->rtnl);
168
169 free(m);
170}
171
02b59d57
TG
172int manager_load_config(Manager *m) {
173 int r;
174
175 /* update timestamp */
2ad8416d 176 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
02b59d57 177
52433f6b 178 r = netdev_load(m);
02b59d57
TG
179 if (r < 0)
180 return r;
181
182 r = network_load(m);
183 if (r < 0)
184 return r;
185
186 return 0;
187}
188
189bool manager_should_reload(Manager *m) {
2ad8416d 190 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
02b59d57
TG
191}
192
505f8da7 193static int manager_udev_process_link(Manager *m, struct udev_device *device) {
11a7f229 194 Link *link = NULL;
667fcc6d 195 int r, ifindex;
f579559b 196
11a7f229
TG
197 assert(m);
198 assert(device);
f579559b 199
505f8da7
TG
200 if (!streq_ptr(udev_device_get_action(device), "add"))
201 return 0;
202
667fcc6d
TG
203 ifindex = udev_device_get_ifindex(device);
204 if (ifindex <= 0) {
205 log_debug("ignoring udev ADD event for device with invalid ifindex");
206 return 0;
207 }
505f8da7 208
667fcc6d
TG
209 r = link_get(m, ifindex, &link);
210 if (r == -ENODEV)
505f8da7 211 return 0;
667fcc6d
TG
212 else if (r < 0)
213 return r;
505f8da7
TG
214
215 r = link_initialized(link, device);
216 if (r < 0)
217 return r;
11a7f229 218
505f8da7
TG
219 return 0;
220}
f579559b 221
505f8da7
TG
222static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
223 Manager *m = userdata;
224 Link *link = NULL;
4d473d5d 225 NetDev *netdev = NULL;
f2236469 226 uint16_t type;
505f8da7
TG
227 char *name;
228 int r, ifindex;
f579559b 229
505f8da7
TG
230 assert(rtnl);
231 assert(message);
f579559b
TG
232 assert(m);
233
f2236469
TG
234 r = sd_rtnl_message_get_type(message, &type);
235 if (r < 0) {
236 log_warning("rtnl: could not get message type");
237 return 0;
238 }
239
505f8da7
TG
240 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
241 if (r < 0 || ifindex <= 0) {
242 log_warning("rtnl: received link message without valid ifindex");
243 return 0;
4d473d5d
TG
244 } else
245 link_get(m, ifindex, &link);
f579559b 246
505f8da7 247 r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &name);
4d473d5d 248 if (r < 0 || !name) {
505f8da7 249 log_warning("rtnl: received link message without valid ifname");
4d473d5d
TG
250 return 0;
251 } else
f2236469 252 netdev_get(m, name, &netdev);
4d473d5d
TG
253
254 switch (type) {
255 case RTM_NEWLINK:
256 if (!link) {
257 /* link is new, so add it */
258 r = link_add(m, message, &link);
259 if (r < 0) {
260 log_debug("could not add new link");
261 return 0;
262 }
263 }
264
265 if (netdev) {
266 /* netdev exists, so make sure the ifindex matches */
505f8da7
TG
267 r = netdev_set_ifindex(netdev, message);
268 if (r < 0) {
269 log_debug("could not set ifindex on netdev");
270 return 0;
271 }
272 }
e1202047 273
f2236469
TG
274 r = link_update(link, message);
275 if (r < 0)
276 return 0;
4d473d5d
TG
277
278 break;
279
280 case RTM_DELLINK:
281 link_drop(link);
282 netdev_drop(netdev);
283
284 break;
285
286 default:
287 assert_not_reached("Received invalid RTNL message type.");
f2236469 288 }
505f8da7
TG
289
290 return 1;
291}
292
293int manager_rtnl_enumerate_links(Manager *m) {
294 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL, *reply = NULL;
295 sd_rtnl_message *link;
296 int r, k;
297
298 assert(m);
299 assert(m->rtnl);
300
301 r = sd_rtnl_message_new_link(m->rtnl, &req, RTM_GETLINK, 0);
302 if (r < 0)
303 return r;
304
305 r = sd_rtnl_message_request_dump(req, true);
f579559b 306 if (r < 0)
bf5332d2 307 return r;
f579559b 308
505f8da7
TG
309 r = sd_rtnl_call(m->rtnl, req, 0, &reply);
310 if (r < 0)
311 return r;
f579559b 312
505f8da7
TG
313 for (link = reply; link; link = sd_rtnl_message_next(link)) {
314 uint16_t type;
315
316 k = sd_rtnl_message_get_type(link, &type);
317 if (k < 0)
318 return k;
319
320 if (type != RTM_NEWLINK)
321 continue;
f579559b 322
505f8da7 323 k = manager_rtnl_process_link(m->rtnl, link, m);
f579559b
TG
324 if (k < 0)
325 r = k;
326 }
327
f579559b
TG
328 return r;
329}
330
331static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
332 Manager *m = userdata;
333 struct udev_monitor *monitor = m->udev_monitor;
7b77ed8c 334 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
f579559b
TG
335
336 device = udev_monitor_receive_device(monitor);
337 if (!device)
338 return -ENOMEM;
339
505f8da7 340 manager_udev_process_link(m, device);
f579559b
TG
341 return 0;
342}
343
344int manager_udev_listen(Manager *m) {
345 int r;
346
505f8da7
TG
347 if (detect_container(NULL) > 0)
348 return 0;
349
350 assert(m->udev_monitor);
351
f579559b
TG
352 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
353 if (r < 0) {
354 log_error("Could not add udev monitor filter: %s", strerror(-r));
355 return r;
356 }
357
f579559b
TG
358 r = udev_monitor_enable_receiving(m->udev_monitor);
359 if (r < 0) {
360 log_error("Could not enable udev monitor");
361 return r;
362 }
363
364 r = sd_event_add_io(m->event,
151b9b96 365 &m->udev_event_source,
f579559b
TG
366 udev_monitor_get_fd(m->udev_monitor),
367 EPOLLIN, manager_dispatch_link_udev,
151b9b96 368 m);
f579559b
TG
369 if (r < 0)
370 return r;
371
372 return 0;
373}
f882c247
TG
374
375int manager_rtnl_listen(Manager *m) {
376 int r;
377
378 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
379 if (r < 0)
380 return r;
381
dd3efc09
TG
382 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
383 if (r < 0)
384 return r;
385
f2236469
TG
386 r = sd_rtnl_add_match(m->rtnl, RTM_DELLINK, &manager_rtnl_process_link, m);
387 if (r < 0)
388 return r;
389
fbbeb65a 390 r = sd_rtnl_add_match(m->rtnl, RTM_NEWADDR, &link_rtnl_process_address, m);
2e9f08ea
TG
391 if (r < 0)
392 return r;
393
fbbeb65a 394 r = sd_rtnl_add_match(m->rtnl, RTM_DELADDR, &link_rtnl_process_address, m);
2e9f08ea
TG
395 if (r < 0)
396 return r;
397
f882c247
TG
398 return 0;
399}
3bef724f 400
1346b1f0
TG
401int manager_bus_listen(Manager *m) {
402 int r;
403
bcbca829
TG
404 assert(m->event);
405
406 if (!m->bus) /* TODO: drop when we can rely on kdbus */
407 return 0;
408
1346b1f0
TG
409 r = sd_bus_attach_event(m->bus, m->event, 0);
410 if (r < 0)
411 return r;
412
413 return 0;
414}
415
bbf7c048
TG
416int manager_save(Manager *m) {
417 Link *link;
418 Iterator i;
419 _cleanup_free_ char *temp_path = NULL;
420 _cleanup_fclose_ FILE *f = NULL;
e375dcde
TG
421 LinkOperationalState operstate = LINK_OPERSTATE_UNKNOWN;
422 const char *operstate_str;
bbf7c048
TG
423 int r;
424
425 assert(m);
426 assert(m->state_file);
427
428 HASHMAP_FOREACH(link, m->links, i) {
429 if (link->flags & IFF_LOOPBACK)
430 continue;
431
e375dcde
TG
432 if (link->operstate > operstate)
433 operstate = link->operstate;
bbf7c048
TG
434 }
435
e375dcde
TG
436 operstate_str = link_operstate_to_string(operstate);
437 assert(operstate_str);
bbf7c048
TG
438
439 r = fopen_temporary(m->state_file, &f, &temp_path);
440 if (r < 0)
441 goto finish;
442
443 fchmod(fileno(f), 0644);
444
445 fprintf(f,
446 "# This is private data. Do not parse.\n"
e375dcde 447 "OPER_STATE=%s\n", operstate_str);
bbf7c048
TG
448
449 fflush(f);
450
451 if (ferror(f) || rename(temp_path, m->state_file) < 0) {
452 r = -errno;
453 unlink(m->state_file);
454 unlink(temp_path);
455 }
456
457finish:
458 if (r < 0)
459 log_error("Failed to save network state to %s: %s", m->state_file, strerror(-r));
460
461 return r;
462}