]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
networkd: fix getting initial state
[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 if (link->dhcp)
77 sd_dhcp_client_free(link->dhcp);
78
79 route_free(link->dhcp_route);
80 link->dhcp_route = NULL;
81
82 address_free(link->dhcp_address);
83 link->dhcp_address = NULL;
84
85 hashmap_remove(link->manager->links, &link->ifindex);
86
87 free(link->ifname);
88
89 free(link);
90 }
91
92 int link_add(Manager *m, struct udev_device *device) {
93 Link *link;
94 Network *network;
95 int r;
96 uint64_t ifindex;
97 const char *devtype;
98
99 assert(m);
100 assert(device);
101
102 ifindex = udev_device_get_ifindex(device);
103 link = hashmap_get(m->links, &ifindex);
104 if (link)
105 return 0;
106
107 r = link_new(m, device, &link);
108 if (r < 0) {
109 log_error("Could not create link: %s", strerror(-r));
110 return r;
111 }
112
113 devtype = udev_device_get_devtype(device);
114 if (streq_ptr(devtype, "bridge")) {
115 r = bridge_set_link(m, link);
116 if (r < 0)
117 return r == -ENOENT ? 0 : r;
118 }
119
120 r = network_get(m, device, &network);
121 if (r < 0)
122 return r == -ENOENT ? 0 : r;
123
124 r = network_apply(m, network, link);
125 if (r < 0)
126 return r;
127
128 return 0;
129 }
130
131 static int link_enter_configured(Link *link) {
132 assert(link);
133 assert(link->state == LINK_STATE_SETTING_ROUTES);
134
135 log_info("Link '%s' configured", link->ifname);
136
137 link->state = LINK_STATE_CONFIGURED;
138
139 return 0;
140 }
141
142 static void link_enter_failed(Link *link) {
143 assert(link);
144
145 link->state = LINK_STATE_FAILED;
146 }
147
148 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
149 Link *link = userdata;
150 int r;
151
152 assert(link->route_messages > 0);
153 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
154 link->state == LINK_STATE_SETTING_ROUTES ||
155 link->state == LINK_STATE_FAILED);
156
157 link->route_messages --;
158
159 if (link->state == LINK_STATE_FAILED)
160 return 1;
161
162 r = sd_rtnl_message_get_errno(m);
163 if (r < 0 && r != -EEXIST)
164 log_warning("Could not set route on interface '%s': %s",
165 link->ifname, strerror(-r));
166
167 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
168 * ignore it */
169 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
170 log_info("Routes set for link '%s'", link->ifname);
171 link_enter_configured(link);
172 }
173
174 return 1;
175 }
176
177 static int link_enter_set_routes(Link *link) {
178 Route *route;
179 int r;
180
181 assert(link);
182 assert(link->network);
183 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
184
185 link->state = LINK_STATE_SETTING_ROUTES;
186
187 if (!link->network->static_routes && !link->dhcp_route)
188 return link_enter_configured(link);
189
190 LIST_FOREACH(static_routes, route, link->network->static_routes) {
191 r = route_configure(route, link, &route_handler);
192 if (r < 0) {
193 log_warning("Could not set routes for link '%s'", link->ifname);
194 link_enter_failed(link);
195 return r;
196 }
197
198 link->route_messages ++;
199 }
200
201 if (link->dhcp_route) {
202 r = route_configure(link->dhcp_route, link, &route_handler);
203 if (r < 0) {
204 log_warning("Could not set routes for link '%s'", link->ifname);
205 link_enter_failed(link);
206 return r;
207 }
208
209 link->route_messages ++;
210 }
211
212 return 0;
213 }
214
215 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
216 Link *link = userdata;
217 int r;
218
219 assert(m);
220 assert(link);
221 assert(link->ifname);
222 assert(link->addr_messages > 0);
223 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
224
225 link->addr_messages --;
226
227 if (link->state == LINK_STATE_FAILED)
228 return 1;
229
230 r = sd_rtnl_message_get_errno(m);
231 if (r < 0 && r != -EEXIST)
232 log_warning("Could not set address on interface '%s': %s",
233 link->ifname, strerror(-r));
234
235 if (link->addr_messages == 0) {
236 log_info("Addresses set for link '%s'", link->ifname);
237 link_enter_set_routes(link);
238 }
239
240 return 1;
241 }
242
243 static int link_enter_set_addresses(Link *link) {
244 Address *address;
245 int r;
246
247 assert(link);
248 assert(link->network);
249 assert(link->state != _LINK_STATE_INVALID);
250
251 link->state = LINK_STATE_SETTING_ADDRESSES;
252
253 if (!link->network->static_addresses && !link->dhcp_address)
254 return link_enter_set_routes(link);
255
256 LIST_FOREACH(static_addresses, address, link->network->static_addresses) {
257 r = address_configure(address, link, &address_handler);
258 if (r < 0) {
259 log_warning("Could not set addresses for link '%s'", link->ifname);
260 link_enter_failed(link);
261 return r;
262 }
263
264 link->addr_messages ++;
265 }
266
267 if (link->dhcp_address) {
268 r = address_configure(link->dhcp_address, link, &address_handler);
269 if (r < 0) {
270 log_warning("Could not set addresses for link '%s'", link->ifname);
271 link_enter_failed(link);
272 return r;
273 }
274
275 link->addr_messages ++;
276 }
277
278 return 0;
279 }
280
281 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
282 Link *link = userdata;
283 int r;
284
285 r = sd_rtnl_message_get_errno(m);
286 if (r < 0) {
287 log_warning("Could not bring up interface '%s': %s",
288 link->ifname, strerror(-r));
289 link_enter_failed(link);
290 }
291
292 return 1;
293 }
294
295 static int link_up(Link *link) {
296 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
297 int r;
298
299 assert(link);
300 assert(link->manager);
301 assert(link->manager->rtnl);
302
303 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
304 if (r < 0) {
305 log_error("Could not allocate RTM_SETLINK message");
306 return r;
307 }
308
309 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
310 if (r < 0) {
311 log_error("Could not set link flags");
312 return r;
313 }
314
315 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
316 if (r < 0) {
317 log_error("Could not send rtnetlink message: %s", strerror(-r));
318 return r;
319 }
320
321 return 0;
322 }
323
324 static int link_bridge_joined(Link *link) {
325 int r;
326
327 assert(link);
328 assert(link->state == LINK_STATE_JOINING_BRIDGE);
329 assert(link->network);
330
331 r = link_up(link);
332 if (r < 0) {
333 link_enter_failed(link);
334 return r;
335 }
336
337 if (!link->network->dhcp) {
338 r = link_enter_set_addresses(link);
339 if (r < 0)
340 link_enter_failed(link);
341 return r;
342 }
343
344 return 0;
345 }
346
347 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
348 Link *link = userdata;
349 int r;
350
351 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
352 assert(link->network);
353
354 if (link->state == LINK_STATE_FAILED)
355 return 1;
356
357 r = sd_rtnl_message_get_errno(m);
358 if (r < 0) {
359 log_warning("Could not join interface '%s' to bridge '%s': %s",
360 link->ifname, link->network->bridge->name, strerror(-r));
361 link_enter_failed(link);
362 return 1;
363 } else
364 log_info("Join interface '%s' to bridge: %s",
365 link->ifname, link->network->bridge->name);
366
367 link_bridge_joined(link);
368
369 return 1;
370 }
371
372 static int link_enter_join_bridge(Link *link) {
373 int r;
374
375 assert(link);
376 assert(link->network);
377 assert(link->state == _LINK_STATE_INVALID);
378
379 link->state = LINK_STATE_JOINING_BRIDGE;
380
381 if (!link->network->bridge)
382 return link_bridge_joined(link);
383
384 r = bridge_join(link->network->bridge, link, &bridge_handler);
385 if (r < 0) {
386 log_warning("Could not join link '%s' to bridge '%s'", link->ifname,
387 link->network->bridge->name);
388 link_enter_failed(link);
389 return r;
390 }
391
392 return 0;
393 }
394
395 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
396 Link *link = userdata;
397 int r;
398
399 r = sd_rtnl_message_get_errno(m);
400 if (r < 0) {
401 log_warning("Could not get state of interface '%s': %s",
402 link->ifname, strerror(-r));
403 link_enter_failed(link);
404 }
405
406 link_update(link, m);
407
408 return 1;
409 }
410
411 static int link_get(Link *link) {
412 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
413 int r;
414
415 assert(link);
416 assert(link->manager);
417 assert(link->manager->rtnl);
418
419 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
420 if (r < 0) {
421 log_error("Could not allocate RTM_GETLINK message");
422 return r;
423 }
424
425 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
426 if (r < 0) {
427 log_error("Could not send rtnetlink message: %s", strerror(-r));
428 return r;
429 }
430
431 return 0;
432 }
433
434 int link_configure(Link *link) {
435 int r;
436
437 assert(link);
438 assert(link->network);
439 assert(link->state == _LINK_STATE_INVALID);
440
441 r = link_get(link);
442 if (r < 0) {
443 link_enter_failed(link);
444 return r;
445 }
446
447 r = link_enter_join_bridge(link);
448 if (r < 0)
449 return r;
450
451 return 0;
452 }
453
454 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
455 Link *link = userdata;
456 int r;
457
458 assert(m);
459 assert(link);
460 assert(link->ifname);
461
462 if (link->state == LINK_STATE_FAILED)
463 return 1;
464
465 r = sd_rtnl_message_get_errno(m);
466 if (r < 0 && r != -EEXIST)
467 log_warning("Could not drop address from interface '%s': %s",
468 link->ifname, strerror(-r));
469
470 return 1;
471 }
472
473 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
474 Link *link = userdata;
475 struct in_addr address;
476 struct in_addr netmask;
477 struct in_addr gateway;
478 int prefixlen;
479 int r;
480
481 if (link->state == LINK_STATE_FAILED)
482 return;
483
484 if (event < 0) {
485 log_warning("DHCP error: %s", strerror(-event));
486 link_enter_failed(link);
487 return;
488 }
489
490 if (event == DHCP_EVENT_NO_LEASE)
491 log_info("IP address in use.");
492
493 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
494 event == DHCP_EVENT_STOP) {
495 address_drop(link->dhcp_address, link, address_drop_handler);
496
497 address_free(link->dhcp_address);
498 link->dhcp_address = NULL;
499
500 route_free(link->dhcp_route);
501 link->dhcp_route = NULL;
502 }
503
504 r = sd_dhcp_client_get_address(client, &address);
505 if (r < 0) {
506 log_warning("DHCP error: no address");
507 link_enter_failed(link);
508 return;
509 }
510
511 r = sd_dhcp_client_get_netmask(client, &netmask);
512 if (r < 0) {
513 log_warning("DHCP error: no netmask");
514 link_enter_failed(link);
515 return;
516 }
517
518 prefixlen = sd_dhcp_client_prefixlen(&netmask);
519 if (prefixlen < 0) {
520 log_warning("DHCP error: no prefixlen");
521 link_enter_failed(link);
522 return;
523 }
524
525 r = sd_dhcp_client_get_router(client, &gateway);
526 if (r < 0) {
527 log_warning("DHCP error: no router");
528 link_enter_failed(link);
529 return;
530 }
531
532 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
533 _cleanup_address_free_ Address *addr = NULL;
534 _cleanup_route_free_ Route *rt = NULL;
535
536 log_info("Received config over DHCPv4");
537
538 r = address_new_dynamic(&addr);
539 if (r < 0) {
540 log_error("Could not allocate address");
541 link_enter_failed(link);
542 return;
543 }
544
545 addr->family = AF_INET;
546 addr->in_addr.in = address;
547 addr->prefixlen = prefixlen;
548 addr->netmask = netmask;
549
550 r = route_new_dynamic(&rt);
551 if (r < 0) {
552 log_error("Could not allocate route");
553 link_enter_failed(link);
554 return;
555 }
556
557 rt->family = AF_INET;
558 rt->in_addr.in = gateway;
559
560 link->dhcp_address = addr;
561 link->dhcp_route = rt;
562 addr = NULL;
563 rt = NULL;
564
565 link_enter_set_addresses(link);
566 }
567
568 return;
569 }
570
571 static int link_acquire_conf(Link *link) {
572 int r;
573
574 assert(link);
575 assert(link->network);
576 assert(link->network->dhcp);
577 assert(link->manager);
578 assert(link->manager->event);
579
580 if (!link->dhcp) {
581 link->dhcp = sd_dhcp_client_new(link->manager->event);
582 if (!link->dhcp)
583 return -ENOMEM;
584
585 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
586 if (r < 0)
587 return r;
588
589 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
590 if (r < 0)
591 return r;
592
593 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
594 if (r < 0)
595 return r;
596 }
597
598 r = sd_dhcp_client_start(link->dhcp);
599 if (r < 0)
600 return r;
601
602 return 0;
603 }
604
605 int link_update(Link *link, sd_rtnl_message *m) {
606 unsigned flags;
607 int r;
608
609 assert(link);
610 assert(m);
611
612 r = sd_rtnl_message_link_get_flags(m, &flags);
613 if (r < 0) {
614 log_warning("Could not get link flags of '%s'", link->ifname);
615 return r;
616 }
617
618 if (link->flags & IFF_UP && !(flags & IFF_UP))
619 log_info("Interface '%s' is down", link->ifname);
620 else if (!(link->flags & IFF_UP) && flags & IFF_UP)
621 log_info("Interface '%s' is up", link->ifname);
622
623 if (link->flags & IFF_LOWER_UP && !(flags & IFF_LOWER_UP)) {
624 log_info("Interface '%s' is disconnected", link->ifname);
625
626 if (link->network->dhcp) {
627 r = sd_dhcp_client_stop(link->dhcp);
628 if (r < 0) {
629 link_enter_failed(link);
630 return r;
631 }
632 }
633 } else if (!(link->flags & IFF_LOWER_UP) && flags & IFF_LOWER_UP) {
634 log_info("Interface '%s' is connected", link->ifname);
635
636 if (link->network->dhcp) {
637 r = link_acquire_conf(link);
638 if (r < 0) {
639 link_enter_failed(link);
640 return r;
641 }
642 }
643 }
644
645 link->flags = flags;
646
647 return 0;
648 }