]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
networkd: distinguish between static and dynamic addresses/routes
[thirdparty/systemd.git] / src / network / networkd-link.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 <netinet/ether.h>
23 #include <linux/if.h>
24
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "util.h"
28
29 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
30 _cleanup_link_free_ Link *link = NULL;
31 const char *mac;
32 struct ether_addr *mac_addr;
33 const char *ifname;
34 int r;
35
36 assert(device);
37 assert(ret);
38
39 link = new0(Link, 1);
40 if (!link)
41 return -ENOMEM;
42
43 link->manager = manager;
44 link->state = _LINK_STATE_INVALID;
45
46 link->ifindex = udev_device_get_ifindex(device);
47 if (link->ifindex <= 0)
48 return -EINVAL;
49
50 mac = udev_device_get_sysattr_value(device, "address");
51 if (mac) {
52 mac_addr = ether_aton(mac);
53 if (mac_addr)
54 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
55 }
56
57 ifname = udev_device_get_sysname(device);
58 link->ifname = strdup(ifname);
59
60 r = hashmap_put(manager->links, &link->ifindex, link);
61 if (r < 0)
62 return r;
63
64 *ret = link;
65 link = NULL;
66
67 return 0;
68 }
69
70 void link_free(Link *link) {
71 if (!link)
72 return;
73
74 assert(link->manager);
75
76 hashmap_remove(link->manager->links, &link->ifindex);
77
78 free(link->ifname);
79
80 free(link);
81 }
82
83 int link_add(Manager *m, struct udev_device *device) {
84 Link *link;
85 Network *network;
86 int r;
87 uint64_t ifindex;
88 const char *devtype;
89
90 assert(m);
91 assert(device);
92
93 ifindex = udev_device_get_ifindex(device);
94 link = hashmap_get(m->links, &ifindex);
95 if (link)
96 return 0;
97
98 r = link_new(m, device, &link);
99 if (r < 0) {
100 log_error("Could not create link: %s", strerror(-r));
101 return r;
102 }
103
104 devtype = udev_device_get_devtype(device);
105 if (streq_ptr(devtype, "bridge")) {
106 r = bridge_set_link(m, link);
107 if (r < 0)
108 return r == -ENOENT ? 0 : r;
109 }
110
111 r = network_get(m, device, &network);
112 if (r < 0)
113 return r == -ENOENT ? 0 : r;
114
115 r = network_apply(m, network, link);
116 if (r < 0)
117 return r;
118
119 return 0;
120 }
121
122 static int link_enter_configured(Link *link) {
123 assert(link);
124 assert(link->state == LINK_STATE_SETTING_ROUTES);
125
126 log_info("Link '%s' configured", link->ifname);
127
128 link->state = LINK_STATE_CONFIGURED;
129
130 return 0;
131 }
132
133 static void link_enter_failed(Link *link) {
134 assert(link);
135
136 link->state = LINK_STATE_FAILED;
137 }
138
139 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
140 Link *link = userdata;
141 int r;
142
143 assert(link->rtnl_messages > 0);
144 assert(link->state == LINK_STATE_SETTING_ROUTES || link->state == LINK_STATE_FAILED);
145
146 link->rtnl_messages --;
147
148 if (link->state == LINK_STATE_FAILED)
149 return 1;
150
151 r = sd_rtnl_message_get_errno(m);
152 if (r < 0 && r != -EEXIST)
153 log_warning("Could not set route on interface '%s': %s",
154 link->ifname, strerror(-r));
155
156 if (link->rtnl_messages == 0) {
157 log_info("Routes set for link '%s'", link->ifname);
158 link_enter_configured(link);
159 }
160
161 return 1;
162 }
163
164 static int link_enter_set_routes(Link *link) {
165 Route *route;
166 int r;
167
168 assert(link);
169 assert(link->network);
170 assert(link->rtnl_messages == 0);
171 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
172
173 link->state = LINK_STATE_SETTING_ROUTES;
174
175 if (!link->network->static_routes)
176 return link_enter_configured(link);
177
178 LIST_FOREACH(static_routes, route, link->network->static_routes) {
179 r = route_configure(route, link, &route_handler);
180 if (r < 0) {
181 log_warning("Could not set routes for link '%s'", link->ifname);
182 link_enter_failed(link);
183 return r;
184 }
185
186 link->rtnl_messages ++;
187 }
188
189 return 0;
190 }
191
192 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
193 Link *link = userdata;
194 int r;
195
196 assert(link->rtnl_messages > 0);
197 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
198
199 link->rtnl_messages --;
200
201 if (link->state == LINK_STATE_FAILED)
202 return 1;
203
204 r = sd_rtnl_message_get_errno(m);
205 if (r < 0 && r != -EEXIST)
206 log_warning("Could not set address on interface '%s': %s",
207 link->ifname, strerror(-r));
208
209 if (link->rtnl_messages == 0) {
210 log_info("Addresses set for link '%s'", link->ifname);
211 link_enter_set_routes(link);
212 }
213
214 return 1;
215 }
216
217 static int link_enter_set_addresses(Link *link) {
218 Address *address;
219 int r;
220
221 assert(link);
222 assert(link->network);
223 assert(link->state == LINK_STATE_JOINING_BRIDGE);
224 assert(link->rtnl_messages == 0);
225
226 link->state = LINK_STATE_SETTING_ADDRESSES;
227
228 if (!link->network->static_addresses)
229 return link_enter_set_routes(link);
230
231 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
232 r = address_configure(address, link, &address_handler);
233 if (r < 0) {
234 log_warning("Could not set addresses for link '%s'", link->ifname);
235 link_enter_failed(link);
236 return r;
237 }
238
239 link->rtnl_messages ++;
240 }
241
242 return 0;
243 }
244
245 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246 Link *link = userdata;
247 int r;
248
249 r = sd_rtnl_message_get_errno(m);
250 if (r < 0) {
251 log_warning("Could not bring up interface '%s': %s",
252 link->ifname, strerror(-r));
253 link_enter_failed(link);
254 }
255
256 return 1;
257 }
258
259 static int link_up(Link *link) {
260 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
261 int r;
262
263 assert(link);
264 assert(link->manager);
265 assert(link->manager->rtnl);
266
267 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
268 if (r < 0) {
269 log_error("Could not allocate RTM_SETLINK message");
270 return r;
271 }
272
273 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
274 if (r < 0) {
275 log_error("Could not set link flags");
276 return r;
277 }
278
279 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
280 if (r < 0) {
281 log_error("Could not send rtnetlink message: %s", strerror(-r));
282 return r;
283 }
284
285 return 0;
286 }
287
288 static int link_bridge_joined(Link *link) {
289 int r;
290
291 assert(link);
292 assert(link->state == LINK_STATE_JOINING_BRIDGE);
293
294 r = link_up(link);
295 if (r < 0) {
296 link_enter_failed(link);
297 return r;
298 }
299
300 r = link_enter_set_addresses(link);
301 if (r < 0) {
302 link_enter_failed(link);
303 return r;
304 }
305
306 return 0;
307 }
308
309 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
310 Link *link = userdata;
311 int r;
312
313 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
314 assert(link->network);
315
316 if (link->state == LINK_STATE_FAILED)
317 return 1;
318
319 r = sd_rtnl_message_get_errno(m);
320 if (r < 0) {
321 log_warning("Could not join interface '%s' to bridge '%s': %s",
322 link->ifname, link->network->bridge->name, strerror(-r));
323 link_enter_failed(link);
324 return 1;
325 } else
326 log_info("Join interface '%s' to bridge: %s",
327 link->ifname, link->network->bridge->name);
328
329 link_bridge_joined(link);
330
331 return 1;
332 }
333
334 static int link_enter_join_bridge(Link *link) {
335 int r;
336
337 assert(link);
338 assert(link->network);
339 assert(link->state == _LINK_STATE_INVALID);
340
341 link->state = LINK_STATE_JOINING_BRIDGE;
342
343 if (!link->network->bridge)
344 return link_bridge_joined(link);
345
346 r = bridge_join(link->network->bridge, link, &bridge_handler);
347 if (r < 0) {
348 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
349 link->network->bridge->name);
350 link_enter_failed(link);
351 return r;
352 }
353
354 return 0;
355 }
356
357 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
358 Link *link = userdata;
359 int r;
360
361 r = sd_rtnl_message_get_errno(m);
362 if (r < 0) {
363 log_warning("Could not get state of interface '%s': %s",
364 link->ifname, strerror(-r));
365 link_enter_failed(link);
366 }
367
368 return 1;
369 }
370
371 static int link_get(Link *link) {
372 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
373 int r;
374
375 assert(link);
376 assert(link->manager);
377 assert(link->manager->rtnl);
378
379 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
380 if (r < 0) {
381 log_error("Could not allocate RTM_GETLINK message");
382 return r;
383 }
384
385 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
386 if (r < 0) {
387 log_error("Could not send rtnetlink message: %s", strerror(-r));
388 return r;
389 }
390
391 return 0;
392 }
393
394 int link_configure(Link *link) {
395 int r;
396
397 assert(link);
398 assert(link->network);
399 assert(link->state == _LINK_STATE_INVALID);
400
401 r = link_get(link);
402 if (r < 0) {
403 link_enter_failed(link);
404 return r;
405 }
406
407 r = link_enter_join_bridge(link);
408 if (r < 0)
409 return r;
410
411 return 0;
412 }
413
414 int link_update(Link *link, sd_rtnl_message *m) {
415 unsigned flags;
416 int r;
417
418 assert(link);
419 assert(m);
420
421 r = sd_rtnl_message_link_get_flags(m, &flags);
422 if (r < 0) {
423 log_warning("Could not get link flags of '%s'", link->ifname);
424 return r;
425 }
426
427 if (link->flags & IFF_UP && !(flags & IFF_UP))
428 log_info("Interface '%s' is down", link->ifname);
429 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
430 log_info("Interface '%s' is up", link->ifname);
431
432 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP))
433 log_info("Interface '%s' is disconnected", link->ifname);
434 else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP)
435 log_info("Interface '%s' is connected", link->ifname);
436
437 link->flags = flags;
438
439 return 0;
440 }