chiark / gitweb /
networkd: refactor link_add() ...
[elogind.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 #include "bus-util.h"
29 #include "net-util.h"
30
31 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
32         _cleanup_link_free_ Link *link = NULL;
33         const char *mac;
34         struct ether_addr *mac_addr;
35         const char *ifname;
36         int r;
37
38         assert(device);
39         assert(ret);
40
41         link = new0(Link, 1);
42         if (!link)
43                 return -ENOMEM;
44
45         link->manager = manager;
46         link->state = _LINK_STATE_INVALID;
47
48         link->ifindex = udev_device_get_ifindex(device);
49         if (link->ifindex <= 0)
50                 return -EINVAL;
51
52         mac = udev_device_get_sysattr_value(device, "address");
53         if (mac) {
54                 mac_addr = ether_aton(mac);
55                 if (mac_addr)
56                         memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
57         }
58
59         ifname = udev_device_get_sysname(device);
60         link->ifname = strdup(ifname);
61
62         r = hashmap_put(manager->links, &link->ifindex, link);
63         if (r < 0)
64                 return r;
65
66         *ret = link;
67         link = NULL;
68
69         return 0;
70 }
71
72 void link_free(Link *link) {
73         if (!link)
74                 return;
75
76         assert(link->manager);
77
78         sd_dhcp_client_free(link->dhcp_client);
79         sd_dhcp_lease_unref(link->dhcp_lease);
80
81         hashmap_remove(link->manager->links, &link->ifindex);
82
83         free(link->ifname);
84
85         free(link);
86 }
87
88 int link_get(Manager *m, int ifindex, Link **ret) {
89         Link *link;
90         uint64_t ifindex_64;
91
92         assert(m);
93         assert(m->links);
94         assert(ifindex);
95         assert(ret);
96
97         ifindex_64 = ifindex;
98         link = hashmap_get(m->links, &ifindex_64);
99         if (!link)
100                 return -ENODEV;
101
102         *ret = link;
103
104         return 0;
105 }
106
107 int link_add(Manager *m, struct udev_device *device, Link **ret) {
108         Link *link;
109         Network *network;
110         int r;
111
112         assert(m);
113         assert(device);
114
115         r = link_new(m, device, &link);
116         if (r < 0)
117                 return r;
118
119         *ret = link;
120
121         r = network_get(m, device, &network);
122         if (r < 0)
123                 return r == -ENOENT ? 0 : r;
124
125         r = network_apply(m, network, link);
126         if (r < 0)
127                 return r;
128
129         return 0;
130 }
131
132 static int link_enter_configured(Link *link) {
133         assert(link);
134         assert(link->state == LINK_STATE_SETTING_ROUTES);
135
136         log_info_link(link, "link configured");
137
138         link->state = LINK_STATE_CONFIGURED;
139
140         return 0;
141 }
142
143 static void link_enter_failed(Link *link) {
144         assert(link);
145
146         log_warning_link(link, "failed");
147
148         link->state = LINK_STATE_FAILED;
149 }
150
151 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
152         Link *link = userdata;
153         int r;
154
155         assert(link->route_messages > 0);
156         assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
157                link->state == LINK_STATE_SETTING_ROUTES ||
158                link->state == LINK_STATE_FAILED);
159
160         link->route_messages --;
161
162         if (link->state == LINK_STATE_FAILED)
163                 return 1;
164
165         r = sd_rtnl_message_get_errno(m);
166         if (r < 0 && r != -EEXIST)
167                 log_struct_link(LOG_WARNING, link,
168                                 "MESSAGE=%s: could not set route: %s",
169                                 link->ifname, strerror(-r),
170                                 "ERRNO=%d", -r,
171                                 NULL);
172
173         /* we might have received an old reply after moving back to SETTING_ADDRESSES,
174          * ignore it */
175         if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
176                 log_debug_link(link, "routes set");
177                 link_enter_configured(link);
178         }
179
180         return 1;
181 }
182
183 static int link_enter_set_routes(Link *link) {
184         Route *rt;
185         int r;
186
187         assert(link);
188         assert(link->network);
189         assert(link->state == LINK_STATE_SETTING_ADDRESSES);
190
191         link->state = LINK_STATE_SETTING_ROUTES;
192
193         if (!link->network->static_routes && !link->dhcp_lease)
194                 return link_enter_configured(link);
195
196         log_debug_link(link, "setting routes");
197
198         LIST_FOREACH(static_routes, rt, link->network->static_routes) {
199                 r = route_configure(rt, link, &route_handler);
200                 if (r < 0) {
201                         log_warning_link(link,
202                                          "could not set routes: %s", strerror(-r));
203                         link_enter_failed(link);
204                         return r;
205                 }
206
207                 link->route_messages ++;
208         }
209
210         if (link->dhcp_lease) {
211                 _cleanup_route_free_ Route *route = NULL;
212                 struct in_addr gateway;
213
214                 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
215                 if (r < 0) {
216                         log_warning_link(link, "DHCP error: no router: %s",
217                                          strerror(-r));
218                         return r;
219                 }
220
221                 r = route_new_dynamic(&route);
222                 if (r < 0) {
223                         log_error_link(link, "Could not allocate route: %s",
224                                        strerror(-r));
225                         return r;
226                 }
227
228                 route->family = AF_INET;
229                 route->in_addr.in = gateway;
230
231                 r = route_configure(route, link, &route_handler);
232                 if (r < 0) {
233                         log_warning_link(link,
234                                          "could not set routes: %s", strerror(-r));
235                         link_enter_failed(link);
236                         return r;
237                 }
238
239                 link->route_messages ++;
240         }
241
242         return 0;
243 }
244
245 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246         Link *link = userdata;
247         int r;
248
249         assert(m);
250         assert(link);
251         assert(link->ifname);
252         assert(link->addr_messages > 0);
253         assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
254
255         link->addr_messages --;
256
257         if (link->state == LINK_STATE_FAILED)
258                 return 1;
259
260         r = sd_rtnl_message_get_errno(m);
261         if (r < 0 && r != -EEXIST)
262                 log_struct_link(LOG_WARNING, link,
263                                 "MESSAGE=%s: could not set address: %s",
264                                 link->ifname, strerror(-r),
265                                 "ERRNO=%d", -r,
266                                 NULL);
267
268         if (link->addr_messages == 0) {
269                 log_debug_link(link, "addresses set");
270                 link_enter_set_routes(link);
271         }
272
273         return 1;
274 }
275
276 static int link_enter_set_addresses(Link *link) {
277         Address *ad;
278         int r;
279
280         assert(link);
281         assert(link->network);
282         assert(link->state != _LINK_STATE_INVALID);
283
284         link->state = LINK_STATE_SETTING_ADDRESSES;
285
286         if (!link->network->static_addresses && !link->dhcp_lease)
287                 return link_enter_set_routes(link);
288
289         log_debug_link(link, "setting addresses");
290
291         LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
292                 r = address_configure(ad, link, &address_handler);
293                 if (r < 0) {
294                         log_warning_link(link,
295                                          "could not set addresses: %s", strerror(-r));
296                         link_enter_failed(link);
297                         return r;
298                 }
299
300                 link->addr_messages ++;
301         }
302
303         if (link->dhcp_lease) {
304                 _cleanup_address_free_ Address *address = NULL;
305                 struct in_addr addr;
306                 struct in_addr netmask;
307                 unsigned prefixlen;
308
309                 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
310                 if (r < 0) {
311                         log_warning_link(link, "DHCP error: no address: %s",
312                                          strerror(-r));
313                         return r;
314                 }
315
316                 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
317                 if (r < 0) {
318                         log_warning_link(link, "DHCP error: no netmask: %s",
319                                          strerror(-r));
320                         return r;
321                 }
322
323                 prefixlen = net_netmask_to_prefixlen(&netmask);
324
325                 r = address_new_dynamic(&address);
326                 if (r < 0) {
327                         log_error_link(link, "Could not allocate address: %s",
328                                        strerror(-r));
329                         return r;
330                 }
331
332                 address->family = AF_INET;
333                 address->in_addr.in = addr;
334                 address->prefixlen = prefixlen;
335                 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
336
337                 r = address_configure(address, link, &address_handler);
338                 if (r < 0) {
339                         log_warning_link(link,
340                                          "could not set addresses: %s", strerror(-r));
341                         link_enter_failed(link);
342                         return r;
343                 }
344
345                 link->addr_messages ++;
346         }
347
348         return 0;
349 }
350
351 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
352         Link *link = userdata;
353         int r;
354
355         assert(m);
356         assert(link);
357         assert(link->ifname);
358
359         if (link->state == LINK_STATE_FAILED)
360                 return 1;
361
362         r = sd_rtnl_message_get_errno(m);
363         if (r < 0 && r != -ENOENT)
364                 log_struct_link(LOG_WARNING, link,
365                                 "MESSAGE=%s: could not drop address: %s",
366                                 link->ifname, strerror(-r),
367                                 "ERRNO=%d", -r,
368                                 NULL);
369
370         return 1;
371 }
372
373 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
374         int r;
375
376         r = sd_bus_message_get_errno(m);
377         if (r < 0)
378                 log_warning("Could not set hostname: %s", strerror(-r));
379
380         return 1;
381 }
382
383 static int set_hostname(sd_bus *bus, const char *hostname) {
384         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
385         int r = 0;
386
387         assert(hostname);
388
389         log_debug("Setting transient hostname: '%s'", hostname);
390
391         if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
392                 log_info("Not connected to system bus, ignoring transient hostname.");
393                 return 0;
394         }
395
396         r = sd_bus_message_new_method_call(
397                         bus,
398                         "org.freedesktop.hostname1",
399                         "/org/freedesktop/hostname1",
400                         "org.freedesktop.hostname1",
401                         "SetHostname",
402                         &m);
403         if (r < 0)
404                 return r;
405
406         r = sd_bus_message_append(m, "sb", hostname, false);
407         if (r < 0)
408                 return r;
409
410         r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
411         if (r < 0)
412                 log_error("Could not set transient hostname: %s", strerror(-r));
413
414         return r;
415 }
416
417 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
418         Link *link = userdata;
419         int r;
420
421         assert(m);
422         assert(link);
423         assert(link->ifname);
424
425         if (link->state == LINK_STATE_FAILED)
426                 return 1;
427
428         r = sd_rtnl_message_get_errno(m);
429         if (r < 0)
430                 log_struct_link(LOG_WARNING, link,
431                                 "MESSAGE=%s: could not set MTU: %s",
432                                 link->ifname, strerror(-r),
433                                 "ERRNO=%d", -r,
434                                 NULL);
435
436         return 1;
437 }
438
439 static int link_set_mtu(Link *link, uint32_t mtu) {
440         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
441         int r;
442
443         assert(link);
444         assert(link->manager);
445         assert(link->manager->rtnl);
446
447         log_debug_link(link, "setting MTU: %" PRIu32, mtu);
448
449         r = sd_rtnl_message_new_link(link->manager->rtnl, RTM_SETLINK,
450                                      link->ifindex, &req);
451         if (r < 0) {
452                 log_error_link(link, "Could not allocate RTM_SETLINK message");
453                 return r;
454         }
455
456         r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
457         if (r < 0) {
458                 log_error_link(link, "Could not append MTU: %s", strerror(-r));
459                 return r;
460         }
461
462         r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
463         if (r < 0) {
464                 log_error_link(link,
465                                "Could not send rtnetlink message: %s", strerror(-r));
466                 return r;
467         }
468
469         return 0;
470 }
471
472 static int dhcp_lease_lost(Link *link) {
473         _cleanup_address_free_ Address *address = NULL;
474         struct in_addr addr;
475         struct in_addr netmask;
476         unsigned prefixlen;
477         int r;
478
479         assert(link);
480         assert(link->dhcp_lease);
481
482         r = address_new_dynamic(&address);
483         if (r >= 0) {
484                 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
485                 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
486                 prefixlen = net_netmask_to_prefixlen(&netmask);
487
488                 address->family = AF_INET;
489                 address->in_addr.in = addr;
490                 address->prefixlen = prefixlen;
491
492                 address_drop(address, link, address_drop_handler);
493         }
494
495         if (link->network->dhcp_mtu) {
496                 uint16_t mtu;
497
498                 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
499                 if (r >= 0 && link->original_mtu != mtu) {
500                         r = link_set_mtu(link, link->original_mtu);
501                         if (r < 0) {
502                                 log_warning_link(link, "DHCP error: could not reset MTU");
503                                 link_enter_failed(link);
504                                 return r;
505                         }
506                 }
507         }
508
509         if (link->network->dhcp_hostname) {
510                 r = set_hostname(link->manager->bus, "");
511                 if (r < 0)
512                         log_error("Failed to reset transient hostname");
513         }
514
515         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
516
517         return 0;
518 }
519
520 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
521         sd_dhcp_lease *lease;
522         struct in_addr address;
523         struct in_addr netmask;
524         struct in_addr gateway;
525         unsigned prefixlen;
526         struct in_addr *nameservers;
527         size_t nameservers_size;
528         int r;
529
530         assert(client);
531         assert(link);
532
533         r = sd_dhcp_client_get_lease(client, &lease);
534         if (r < 0) {
535                 log_warning_link(link, "DHCP error: no lease: %s",
536                                  strerror(-r));
537                 return r;
538         }
539
540         r = sd_dhcp_lease_get_address(lease, &address);
541         if (r < 0) {
542                 log_warning_link(link, "DHCP error: no address: %s",
543                                  strerror(-r));
544                 return r;
545         }
546
547         r = sd_dhcp_lease_get_netmask(lease, &netmask);
548         if (r < 0) {
549                 log_warning_link(link, "DHCP error: no netmask: %s",
550                                  strerror(-r));
551                 return r;
552         }
553
554         prefixlen = net_netmask_to_prefixlen(&netmask);
555
556         r = sd_dhcp_lease_get_router(lease, &gateway);
557         if (r < 0) {
558                 log_warning_link(link, "DHCP error: no router: %s",
559                                  strerror(-r));
560                 return r;
561         }
562
563         log_struct_link(LOG_INFO, link,
564                         "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
565                          link->ifname,
566                          ADDRESS_FMT_VAL(address),
567                          prefixlen,
568                          ADDRESS_FMT_VAL(gateway),
569                          "ADDRESS=%u.%u.%u.%u",
570                          ADDRESS_FMT_VAL(address),
571                          "PREFIXLEN=%u",
572                          prefixlen,
573                          "GATEWAY=%u.%u.%u.%u",
574                          ADDRESS_FMT_VAL(gateway),
575                          NULL);
576
577         link->dhcp_lease = lease;
578
579         if (link->network->dhcp_dns) {
580                 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
581                 if (r >= 0) {
582                         r = manager_update_resolv_conf(link->manager);
583                         if (r < 0)
584                                 log_error("Failed to update resolv.conf");
585                 }
586         }
587
588         if (link->network->dhcp_mtu) {
589                 uint16_t mtu;
590
591                 r = sd_dhcp_lease_get_mtu(lease, &mtu);
592                 if (r >= 0) {
593                         r = link_set_mtu(link, mtu);
594                         if (r < 0)
595                                 log_error_link(link, "Failed to set MTU "
596                                                "to %" PRIu16, mtu);
597                 }
598         }
599
600         if (link->network->dhcp_hostname) {
601                 const char *hostname;
602
603                 r = sd_dhcp_lease_get_hostname(lease, &hostname);
604                 if (r >= 0) {
605                         r = set_hostname(link->manager->bus, hostname);
606                         if (r < 0)
607                                 log_error("Failed to set transient hostname "
608                                           "to '%s'", hostname);
609                 }
610         }
611
612         link_enter_set_addresses(link);
613
614         return 0;
615 }
616
617 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
618         Link *link = userdata;
619         int r;
620
621         assert(link);
622         assert(link->network);
623         assert(link->manager);
624
625         if (link->state == LINK_STATE_FAILED)
626                 return;
627
628         switch (event) {
629                 case DHCP_EVENT_NO_LEASE:
630                         log_debug_link(link, "IP address in use.");
631                         break;
632                 case DHCP_EVENT_EXPIRED:
633                 case DHCP_EVENT_STOP:
634                 case DHCP_EVENT_IP_CHANGE:
635                         if (link->network->dhcp_critical) {
636                                 log_error_link(link, "DHCPv4 connection considered system critical, "
637                                                "ignoring request to reconfigure it.");
638                                 return;
639                         }
640
641                         if (link->dhcp_lease) {
642                                 r = dhcp_lease_lost(link);
643                                 if (r < 0) {
644                                         link_enter_failed(link);
645                                         return;
646                                 }
647                         }
648
649                         if (event == DHCP_EVENT_IP_CHANGE) {
650                                 r = dhcp_lease_acquired(client, link);
651                                 if (r < 0) {
652                                         link_enter_failed(link);
653                                         return;
654                                 }
655                         }
656
657                         break;
658                 case DHCP_EVENT_IP_ACQUIRE:
659                         r = dhcp_lease_acquired(client, link);
660                         if (r < 0) {
661                                 link_enter_failed(link);
662                                 return;
663                         }
664                         break;
665                 default:
666                         if (event < 0)
667                                 log_warning_link(link, "DHCP error: %s", strerror(-event));
668                         else
669                                 log_warning_link(link, "DHCP unknown event: %d", event);
670                         break;
671         }
672
673         return;
674 }
675
676 static int link_acquire_conf(Link *link) {
677         int r;
678
679         assert(link);
680         assert(link->network);
681         assert(link->network->dhcp);
682         assert(link->manager);
683         assert(link->manager->event);
684
685         if (!link->dhcp_client) {
686                 r = sd_dhcp_client_new(&link->dhcp_client);
687                 if (r < 0)
688                         return r;
689
690                 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
691                 if (r < 0)
692                         return r;
693
694                 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
695                 if (r < 0)
696                         return r;
697
698                 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
699                 if (r < 0)
700                         return r;
701
702                 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
703                 if (r < 0)
704                         return r;
705
706                 if (link->network->dhcp_mtu) {
707                         r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
708                         if (r < 0)
709                                 return r;
710                 }
711         }
712
713         log_debug_link(link, "acquiring DHCPv4 lease");
714
715         r = sd_dhcp_client_start(link->dhcp_client);
716         if (r < 0)
717                 return r;
718
719         return 0;
720 }
721
722 static int link_update_flags(Link *link, unsigned flags) {
723         int r;
724
725         assert(link);
726         assert(link->network);
727
728         if (link->state == LINK_STATE_FAILED)
729                 return 0;
730
731         if (link->flags == flags) {
732                 log_debug_link(link, "link status unchanged: %#.8x", flags);
733                 return 0;
734         }
735
736         if ((link->flags & IFF_UP) != (flags & IFF_UP))
737                 log_info_link(link,
738                               "link is %s", flags & IFF_UP ? "up": "down");
739
740         if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
741                 if (flags & IFF_LOWER_UP) {
742                         log_info_link(link, "carrier on");
743
744                         if (link->network->dhcp) {
745                                 r = link_acquire_conf(link);
746                                 if (r < 0) {
747                                         log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
748                                         link_enter_failed(link);
749                                         return r;
750                                 }
751                         }
752                 } else {
753                         log_info_link(link, "carrier off");
754
755                         if (link->network->dhcp) {
756                                 r = sd_dhcp_client_stop(link->dhcp_client);
757                                 if (r < 0) {
758                                         log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
759                                         link_enter_failed(link);
760                                         return r;
761                                 }
762                         }
763                 }
764         }
765
766         log_debug_link(link,
767                        "link status updated: %#.8x -> %#.8x", link->flags, flags);
768
769         link->flags = flags;
770
771         return 0;
772 }
773
774 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
775         Link *link = userdata;
776         int r;
777
778         assert(link);
779
780         if (link->state == LINK_STATE_FAILED)
781                 return 1;
782
783         r = sd_rtnl_message_get_errno(m);
784         if (r < 0) {
785                 log_struct_link(LOG_ERR, link,
786                                 "MESSAGE=%s: could not bring up interface: %s",
787                                 link->ifname, strerror(-r),
788                                 "ERRNO=%d", -r,
789                                 NULL);
790                 link_enter_failed(link);
791                 return 1;
792         }
793
794         link_update_flags(link, link->flags | IFF_UP);
795
796         return 1;
797 }
798
799 static int link_up(Link *link) {
800         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
801         int r;
802
803         assert(link);
804         assert(link->manager);
805         assert(link->manager->rtnl);
806
807         log_debug_link(link, "bringing link up");
808
809         r = sd_rtnl_message_new_link(link->manager->rtnl, RTM_SETLINK,
810                                      link->ifindex, &req);
811         if (r < 0) {
812                 log_error_link(link, "Could not allocate RTM_SETLINK message");
813                 return r;
814         }
815
816         r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
817         if (r < 0) {
818                 log_error_link(link, "Could not set link flags: %s", strerror(-r));
819                 return r;
820         }
821
822         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
823         if (r < 0) {
824                 log_error_link(link,
825                                "Could not send rtnetlink message: %s", strerror(-r));
826                 return r;
827         }
828
829         return 0;
830 }
831
832 static int link_enslaved(Link *link) {
833         int r;
834
835         assert(link);
836         assert(link->state == LINK_STATE_ENSLAVING);
837         assert(link->network);
838
839         r = link_up(link);
840         if (r < 0) {
841                 link_enter_failed(link);
842                 return r;
843         }
844
845         if (!link->network->dhcp)
846                 return link_enter_set_addresses(link);
847
848         return 0;
849 }
850
851 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
852         Link *link = userdata;
853         int r;
854
855         assert(link);
856         assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
857         assert(link->network);
858
859         link->enslaving --;
860
861         if (link->state == LINK_STATE_FAILED)
862                 return 1;
863
864         r = sd_rtnl_message_get_errno(m);
865         if (r < 0) {
866                 log_struct_link(LOG_ERR, link,
867                                 "MESSAGE=%s: could not enslave: %s",
868                                 link->ifname, strerror(-r),
869                                 "ERRNO=%d", -r,
870                                 NULL);
871                 link_enter_failed(link);
872                 return 1;
873         }
874
875         log_debug_link(link, "enslaved");
876
877         if (link->enslaving == 0)
878                 link_enslaved(link);
879
880         return 1;
881 }
882
883 static int link_enter_enslave(Link *link) {
884         NetDev *vlan;
885         Iterator i;
886         int r;
887
888         assert(link);
889         assert(link->network);
890         assert(link->state == _LINK_STATE_INVALID);
891
892         link->state = LINK_STATE_ENSLAVING;
893
894         if (!link->network->bridge && !link->network->bond &&
895             hashmap_isempty(link->network->vlans))
896                 return link_enslaved(link);
897
898         if (link->network->bridge) {
899                 log_struct_link(LOG_DEBUG, link,
900                                 "MESSAGE=%s: enslaving by '%s'",
901                                 link->ifname, link->network->bridge->name,
902                                 NETDEV(link->network->bridge),
903                                 NULL);
904
905                 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
906                 if (r < 0) {
907                         log_struct_link(LOG_WARNING, link,
908                                         "MESSAGE=%s: could not enslave by '%s': %s",
909                                         link->ifname, link->network->bridge->name, strerror(-r),
910                                         NETDEV(link->network->bridge),
911                                         NULL);
912                         link_enter_failed(link);
913                         return r;
914                 }
915
916                 link->enslaving ++;
917         }
918
919         HASHMAP_FOREACH(vlan, link->network->vlans, i) {
920                 log_struct_link(LOG_DEBUG, link,
921                                 "MESSAGE=%s: enslaving by '%s'",
922                                 link->ifname, vlan->name, NETDEV(vlan), NULL);
923
924                 r = netdev_enslave(vlan, link, &enslave_handler);
925                 if (r < 0) {
926                         log_struct_link(LOG_WARNING, link,
927                                         "MESSAGE=%s: could not enslave by '%s': %s",
928                                         link->ifname, vlan->name, strerror(-r),
929                                         NETDEV(vlan), NULL);
930                         link_enter_failed(link);
931                         return r;
932                 }
933
934                 link->enslaving ++;
935         }
936
937         return 0;
938 }
939
940 static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
941                                 void *userdata) {
942         Link *link = userdata;
943         int r;
944
945         assert(link);
946
947         if (link->state == LINK_STATE_FAILED)
948                 return 1;
949
950         r = sd_rtnl_message_get_errno(m);
951         if (r < 0) {
952                 log_struct_link(LOG_ERR, link,
953                                 "MESSAGE=%s: could not get state: %s",
954                                 link->ifname, strerror(-r),
955                                 "ERRNO=%d", -r,
956                                 NULL);
957                 link_enter_failed(link);
958                 return 1;
959         }
960
961         log_debug_link(link, "got link state");
962
963         link_update(link, m);
964
965         return 1;
966 }
967
968 static int link_getlink(Link *link) {
969         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
970         int r;
971
972         assert(link);
973         assert(link->manager);
974         assert(link->manager->rtnl);
975
976         log_debug_link(link, "requesting link status");
977
978         r = sd_rtnl_message_new_link(link->manager->rtnl, RTM_GETLINK,
979                                      link->ifindex, &req);
980         if (r < 0) {
981                 log_error_link(link, "Could not allocate RTM_GETLINK message");
982                 return r;
983         }
984
985         r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
986                                link, 0, NULL);
987         if (r < 0) {
988                 log_error_link(link,
989                                "Could not send rtnetlink message: %s", strerror(-r));
990                 return r;
991         }
992
993         return 0;
994 }
995
996 int link_configure(Link *link) {
997         int r;
998
999         assert(link);
1000         assert(link->network);
1001         assert(link->state == _LINK_STATE_INVALID);
1002
1003         r = link_getlink(link);
1004         if (r < 0) {
1005                 link_enter_failed(link);
1006                 return r;
1007         }
1008
1009         return link_enter_enslave(link);
1010 }
1011
1012 int link_update(Link *link, sd_rtnl_message *m) {
1013         unsigned flags;
1014         void *data;
1015         uint16_t type;
1016         int r;
1017
1018         assert(link);
1019         assert(m);
1020
1021         if (link->state == LINK_STATE_FAILED)
1022                 return 0;
1023
1024         r = sd_rtnl_message_link_get_flags(m, &flags);
1025         if (r < 0) {
1026                 log_warning_link(link, "Could not get link flags");
1027                 return r;
1028         }
1029
1030         while (sd_rtnl_message_read(m, &type, &data) > 0) {
1031                 if (type == IFLA_MTU && link->network->dhcp &&
1032                     link->network->dhcp_mtu && !link->original_mtu) {
1033                         link->original_mtu = *(uint16_t *) data;
1034                         log_debug_link(link, "saved original MTU: %" PRIu16,
1035                                        link->original_mtu);
1036                 }
1037         }
1038
1039         return link_update_flags(link, flags);
1040 }