]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-manager.c
networkd: dhcp - only set the MTU option once
[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
TG
22#include <resolv.h>
23
f579559b
TG
24#include "path-util.h"
25#include "networkd.h"
26#include "libudev-private.h"
7b77ed8c 27#include "udev-util.h"
3bef724f 28#include "mkdir.h"
f579559b 29
2ad8416d
ZJS
30const char* const network_dirs[] = {
31 "/etc/systemd/network",
32 "/run/systemd/network",
33 "/usr/lib/systemd/network",
34#ifdef HAVE_SPLIT_USER
35 "/lib/systemd/network",
36#endif
37 NULL};
38
f579559b
TG
39int manager_new(Manager **ret) {
40 _cleanup_manager_free_ Manager *m = NULL;
41 int r;
42
43 m = new0(Manager, 1);
44 if (!m)
45 return -ENOMEM;
46
afc6adb5 47 r = sd_event_default(&m->event);
f579559b
TG
48 if (r < 0)
49 return r;
50
cde93897
LP
51 sd_event_set_watchdog(m->event, true);
52
dd3efc09 53 r = sd_rtnl_open(RTMGRP_LINK | RTMGRP_IPV4_IFADDR, &m->rtnl);
f579559b
TG
54 if (r < 0)
55 return r;
56
57 m->udev = udev_new();
58 if (!m->udev)
59 return -ENOMEM;
60
61 m->udev_monitor = udev_monitor_new_from_netlink(m->udev, "udev");
62 if (!m->udev_monitor)
63 return -ENOMEM;
64
65 m->links = hashmap_new(uint64_hash_func, uint64_compare_func);
66 if (!m->links)
67 return -ENOMEM;
68
02b59d57
TG
69 m->bridges = hashmap_new(string_hash_func, string_compare_func);
70 if (!m->bridges)
71 return -ENOMEM;
72
f579559b
TG
73 LIST_HEAD_INIT(m->networks);
74
f579559b
TG
75 *ret = m;
76 m = NULL;
77
78 return 0;
79}
80
81void manager_free(Manager *m) {
0617ffab 82 Network *network;
02b59d57 83 Bridge *bridge;
0617ffab
TG
84 Link *link;
85
f579559b
TG
86 udev_monitor_unref(m->udev_monitor);
87 udev_unref(m->udev);
88 sd_event_source_unref(m->udev_event_source);
89 sd_event_unref(m->event);
0617ffab
TG
90
91 while ((network = m->networks))
92 network_free(network);
93
94 while ((link = hashmap_first(m->links)))
95 link_free(link);
f579559b 96 hashmap_free(m->links);
0617ffab 97
02b59d57
TG
98 while ((bridge = hashmap_first(m->bridges)))
99 bridge_free(bridge);
100 hashmap_free(m->bridges);
101
f579559b
TG
102 sd_rtnl_unref(m->rtnl);
103
104 free(m);
105}
106
02b59d57
TG
107int manager_load_config(Manager *m) {
108 int r;
109
110 /* update timestamp */
2ad8416d 111 paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, true);
02b59d57
TG
112
113 r = bridge_load(m);
114 if (r < 0)
115 return r;
116
117 r = network_load(m);
118 if (r < 0)
119 return r;
120
121 return 0;
122}
123
124bool manager_should_reload(Manager *m) {
2ad8416d 125 return paths_check_timestamp(network_dirs, &m->network_dirs_ts_usec, false);
02b59d57
TG
126}
127
f579559b
TG
128static int manager_process_link(Manager *m, struct udev_device *device) {
129 Link *link;
130 int r;
131
132 if (streq_ptr(udev_device_get_action(device), "remove")) {
133 uint64_t ifindex;
134
449f7554 135 log_debug("%s: link removed", udev_device_get_sysname(device));
002f5de9 136
f579559b
TG
137 ifindex = udev_device_get_ifindex(device);
138 link = hashmap_get(m->links, &ifindex);
139 if (!link)
140 return 0;
141
142 link_free(link);
143 } else {
aa3437a5 144 r = link_add(m, device, &link);
f579559b 145 if (r < 0) {
2672953b
TG
146 if (r == -EEXIST)
147 log_debug("%s: link already exists, ignoring",
aa3437a5 148 link->ifname);
2672953b
TG
149 else
150 log_error("%s: could not handle link: %s",
151 udev_device_get_sysname(device),
152 strerror(-r));
153 } else
aa3437a5
TG
154 log_debug("%s: link (with ifindex %" PRIu64") added",
155 link->ifname, link->ifindex);
f579559b
TG
156 }
157
158 return 0;
159}
160
161int manager_udev_enumerate_links(Manager *m) {
bf5332d2 162 _cleanup_udev_enumerate_unref_ struct udev_enumerate *e = NULL;
f579559b 163 struct udev_list_entry *item = NULL, *first = NULL;
f579559b
TG
164 int r;
165
166 assert(m);
167
168 e = udev_enumerate_new(m->udev);
bf5332d2
LP
169 if (!e)
170 return -ENOMEM;
f579559b
TG
171
172 r = udev_enumerate_add_match_subsystem(e, "net");
173 if (r < 0)
bf5332d2 174 return r;
f579559b 175
e1202047
LP
176 r = udev_enumerate_add_match_is_initialized(e);
177 if (r < 0)
178 return r;
179
f579559b
TG
180 r = udev_enumerate_scan_devices(e);
181 if (r < 0)
bf5332d2 182 return r;
f579559b
TG
183
184 first = udev_enumerate_get_list_entry(e);
185 udev_list_entry_foreach(item, first) {
bf5332d2 186 _cleanup_udev_device_unref_ struct udev_device *d = NULL;
f579559b
TG
187 int k;
188
189 d = udev_device_new_from_syspath(m->udev, udev_list_entry_get_name(item));
bf5332d2
LP
190 if (!d)
191 return -ENOMEM;
f579559b 192
bf5332d2 193 k = manager_process_link(m, d);
f579559b
TG
194 if (k < 0)
195 r = k;
196 }
197
f579559b
TG
198 return r;
199}
200
201static int manager_dispatch_link_udev(sd_event_source *source, int fd, uint32_t revents, void *userdata) {
202 Manager *m = userdata;
203 struct udev_monitor *monitor = m->udev_monitor;
7b77ed8c 204 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
f579559b
TG
205
206 device = udev_monitor_receive_device(monitor);
207 if (!device)
208 return -ENOMEM;
209
7b77ed8c 210 manager_process_link(m, device);
f579559b
TG
211 return 0;
212}
213
214int manager_udev_listen(Manager *m) {
215 int r;
216
217 r = udev_monitor_filter_add_match_subsystem_devtype(m->udev_monitor, "net", NULL);
218 if (r < 0) {
219 log_error("Could not add udev monitor filter: %s", strerror(-r));
220 return r;
221 }
222
f579559b
TG
223 r = udev_monitor_enable_receiving(m->udev_monitor);
224 if (r < 0) {
225 log_error("Could not enable udev monitor");
226 return r;
227 }
228
229 r = sd_event_add_io(m->event,
230 udev_monitor_get_fd(m->udev_monitor),
231 EPOLLIN, manager_dispatch_link_udev,
232 m, &m->udev_event_source);
233 if (r < 0)
234 return r;
235
236 return 0;
237}
f882c247 238
dd3efc09
TG
239static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
240 Manager *m = userdata;
241 Link *link;
8b264404 242 uint64_t ifindex_64;
dd3efc09
TG
243 int r, ifindex;
244
245 r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
d0d311d6
TG
246 if (r < 0) {
247 log_debug("received RTM_NEWLINK message without valid ifindex");
dd3efc09 248 return 0;
d0d311d6 249 }
dd3efc09 250
8b264404
TG
251 ifindex_64 = ifindex;
252 link = hashmap_get(m->links, &ifindex_64);
d0d311d6 253 if (!link) {
8b264404 254 log_debug("received RTM_NEWLINK message for untracked ifindex %d", ifindex);
dd3efc09 255 return 0;
d0d311d6 256 }
dd3efc09 257
06a6e593
TG
258 /* only track the status of links we want to manage */
259 if (link->network) {
260 r = link_update(link, message);
261 if (r < 0)
262 return 0;
d0d311d6 263 } else
8b264404 264 log_debug("%s: received RTM_NEWLINK message for unmanaged link", link->ifname);
dd3efc09
TG
265
266 return 1;
267}
268
f882c247
TG
269int manager_rtnl_listen(Manager *m) {
270 int r;
271
272 r = sd_rtnl_attach_event(m->rtnl, m->event, 0);
273 if (r < 0)
274 return r;
275
dd3efc09
TG
276 r = sd_rtnl_add_match(m->rtnl, RTM_NEWLINK, &manager_rtnl_process_link, m);
277 if (r < 0)
278 return r;
279
f882c247
TG
280 return 0;
281}
3bef724f
TG
282
283static void append_dns(FILE *f, struct in_addr *dns, unsigned char family, unsigned *count) {
284 char buf[INET6_ADDRSTRLEN];
285 const char *address;
286
287 address = inet_ntop(family, dns, buf, INET6_ADDRSTRLEN);
288 if (!address) {
289 log_warning("Invalid DNS address. Ignoring.");
290 return;
291 }
292
293 if (*count == MAXNS)
f3621dec
TG
294 fputs("# Too many DNS servers configured, the following entries "
295 "will be ignored\n", f);
3bef724f
TG
296
297 fprintf(f, "nameserver %s\n", address);
298
299 (*count) ++;
300}
301
302int manager_update_resolv_conf(Manager *m) {
303 _cleanup_free_ char *temp_path = NULL;
304 _cleanup_fclose_ FILE *f = NULL;
305 Link *link;
306 Iterator i;
307 unsigned count = 0;
308 int r;
309
310 assert(m);
311
312 r = mkdir_safe_label("/run/systemd/network", 0755, 0, 0);
313 if (r < 0)
314 return r;
315
316 r = fopen_temporary("/run/systemd/network/resolv.conf", &f, &temp_path);
317 if (r < 0)
318 return r;
319
320 fchmod(fileno(f), 0644);
321
322 fputs("# This file is managed by systemd-networkd(8). Do not edit.\n", f);
323
324 HASHMAP_FOREACH(link, m->links, i) {
325 if (link->dhcp) {
326 struct in_addr **nameservers;
327
328 r = sd_dhcp_client_get_dns(link->dhcp, &nameservers);
329 if (r >= 0) {
330 unsigned j;
331
332 for (j = 0; nameservers[j]; j++)
333 append_dns(f, nameservers[j], AF_INET, &count);
334 }
335 }
336 }
337
338 HASHMAP_FOREACH(link, m->links, i)
339 if (link->network && link->network->dns)
340 append_dns(f, &link->network->dns->in_addr.in,
341 link->network->dns->family, &count);
342
343 fflush(f);
344
345 if (ferror(f) || rename(temp_path, "/run/systemd/network/resolv.conf") < 0) {
346 r = -errno;
347 unlink("/run/systemd/network/resolv.conf");
348 unlink(temp_path);
349 return r;
350 }
351
352 return 0;
353}