chiark / gitweb /
e2d61ae490f4024b986e13858018f0428ff53a19
[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 = NULL;
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                         &m,
399                         "org.freedesktop.hostname1",
400                         "/org/freedesktop/hostname1",
401                         "org.freedesktop.hostname1",
402                         "SetHostname");
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, &req,
450                                      RTM_SETLINK, link->ifindex);
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         log_warning_link(link, "DHCP lease lost");
483
484         r = address_new_dynamic(&address);
485         if (r >= 0) {
486                 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
487                 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
488                 prefixlen = net_netmask_to_prefixlen(&netmask);
489
490                 address->family = AF_INET;
491                 address->in_addr.in = addr;
492                 address->prefixlen = prefixlen;
493
494                 address_drop(address, link, address_drop_handler);
495         }
496
497         if (link->network->dhcp_mtu) {
498                 uint16_t mtu;
499
500                 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
501                 if (r >= 0 && link->original_mtu != mtu) {
502                         r = link_set_mtu(link, link->original_mtu);
503                         if (r < 0) {
504                                 log_warning_link(link, "DHCP error: could not reset MTU");
505                                 link_enter_failed(link);
506                                 return r;
507                         }
508                 }
509         }
510
511         if (link->network->dhcp_hostname) {
512                 const char *hostname = NULL;
513
514                 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
515                 if (r >= 0 && hostname) {
516                         r = set_hostname(link->manager->bus, "");
517                         if (r < 0)
518                                 log_error("Failed to reset transient hostname");
519                 }
520         }
521
522         link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
523
524         return 0;
525 }
526
527 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
528         sd_dhcp_lease *lease;
529         struct in_addr address;
530         struct in_addr netmask;
531         struct in_addr gateway;
532         unsigned prefixlen;
533         struct in_addr *nameservers;
534         size_t nameservers_size;
535         int r;
536
537         assert(client);
538         assert(link);
539
540         r = sd_dhcp_client_get_lease(client, &lease);
541         if (r < 0) {
542                 log_warning_link(link, "DHCP error: no lease: %s",
543                                  strerror(-r));
544                 return r;
545         }
546
547         r = sd_dhcp_lease_get_address(lease, &address);
548         if (r < 0) {
549                 log_warning_link(link, "DHCP error: no address: %s",
550                                  strerror(-r));
551                 return r;
552         }
553
554         r = sd_dhcp_lease_get_netmask(lease, &netmask);
555         if (r < 0) {
556                 log_warning_link(link, "DHCP error: no netmask: %s",
557                                  strerror(-r));
558                 return r;
559         }
560
561         prefixlen = net_netmask_to_prefixlen(&netmask);
562
563         r = sd_dhcp_lease_get_router(lease, &gateway);
564         if (r < 0) {
565                 log_warning_link(link, "DHCP error: no router: %s",
566                                  strerror(-r));
567                 return r;
568         }
569
570         log_struct_link(LOG_INFO, link,
571                         "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
572                          link->ifname,
573                          ADDRESS_FMT_VAL(address),
574                          prefixlen,
575                          ADDRESS_FMT_VAL(gateway),
576                          "ADDRESS=%u.%u.%u.%u",
577                          ADDRESS_FMT_VAL(address),
578                          "PREFIXLEN=%u",
579                          prefixlen,
580                          "GATEWAY=%u.%u.%u.%u",
581                          ADDRESS_FMT_VAL(gateway),
582                          NULL);
583
584         link->dhcp_lease = lease;
585
586         if (link->network->dhcp_dns) {
587                 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
588                 if (r >= 0) {
589                         r = manager_update_resolv_conf(link->manager);
590                         if (r < 0)
591                                 log_error("Failed to update resolv.conf");
592                 }
593         }
594
595         if (link->network->dhcp_mtu) {
596                 uint16_t mtu;
597
598                 r = sd_dhcp_lease_get_mtu(lease, &mtu);
599                 if (r >= 0) {
600                         r = link_set_mtu(link, mtu);
601                         if (r < 0)
602                                 log_error_link(link, "Failed to set MTU "
603                                                "to %" PRIu16, mtu);
604                 }
605         }
606
607         if (link->network->dhcp_hostname) {
608                 const char *hostname;
609
610                 r = sd_dhcp_lease_get_hostname(lease, &hostname);
611                 if (r >= 0) {
612                         r = set_hostname(link->manager->bus, hostname);
613                         if (r < 0)
614                                 log_error("Failed to set transient hostname "
615                                           "to '%s'", hostname);
616                 }
617         }
618
619         link_enter_set_addresses(link);
620
621         return 0;
622 }
623
624 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
625         Link *link = userdata;
626         int r;
627
628         assert(link);
629         assert(link->network);
630         assert(link->manager);
631
632         if (link->state == LINK_STATE_FAILED)
633                 return;
634
635         switch (event) {
636                 case DHCP_EVENT_NO_LEASE:
637                         log_debug_link(link, "IP address in use.");
638                         break;
639                 case DHCP_EVENT_EXPIRED:
640                 case DHCP_EVENT_STOP:
641                 case DHCP_EVENT_IP_CHANGE:
642                         if (link->network->dhcp_critical) {
643                                 log_error_link(link, "DHCPv4 connection considered system critical, "
644                                                "ignoring request to reconfigure it.");
645                                 return;
646                         }
647
648                         if (link->dhcp_lease) {
649                                 r = dhcp_lease_lost(link);
650                                 if (r < 0) {
651                                         link_enter_failed(link);
652                                         return;
653                                 }
654                         }
655
656                         if (event == DHCP_EVENT_IP_CHANGE) {
657                                 r = dhcp_lease_acquired(client, link);
658                                 if (r < 0) {
659                                         link_enter_failed(link);
660                                         return;
661                                 }
662                         }
663
664                         break;
665                 case DHCP_EVENT_IP_ACQUIRE:
666                         r = dhcp_lease_acquired(client, link);
667                         if (r < 0) {
668                                 link_enter_failed(link);
669                                 return;
670                         }
671                         break;
672                 default:
673                         if (event < 0)
674                                 log_warning_link(link, "DHCP error: %s", strerror(-event));
675                         else
676                                 log_warning_link(link, "DHCP unknown event: %d", event);
677                         break;
678         }
679
680         return;
681 }
682
683 static int link_acquire_conf(Link *link) {
684         int r;
685
686         assert(link);
687         assert(link->network);
688         assert(link->network->dhcp);
689         assert(link->manager);
690         assert(link->manager->event);
691
692         if (!link->dhcp_client) {
693                 r = sd_dhcp_client_new(&link->dhcp_client);
694                 if (r < 0)
695                         return r;
696
697                 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
698                 if (r < 0)
699                         return r;
700
701                 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
702                 if (r < 0)
703                         return r;
704
705                 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
706                 if (r < 0)
707                         return r;
708
709                 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
710                 if (r < 0)
711                         return r;
712
713                 if (link->network->dhcp_mtu) {
714                         r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
715                         if (r < 0)
716                                 return r;
717                 }
718         }
719
720         log_debug_link(link, "acquiring DHCPv4 lease");
721
722         r = sd_dhcp_client_start(link->dhcp_client);
723         if (r < 0)
724                 return r;
725
726         return 0;
727 }
728
729 static int link_update_flags(Link *link, unsigned flags) {
730         int r;
731
732         assert(link);
733         assert(link->network);
734
735         if (link->state == LINK_STATE_FAILED)
736                 return 0;
737
738         if (link->flags == flags) {
739                 log_debug_link(link, "link status unchanged: %#.8x", flags);
740                 return 0;
741         }
742
743         if ((link->flags & IFF_UP) != (flags & IFF_UP))
744                 log_info_link(link,
745                               "link is %s", flags & IFF_UP ? "up": "down");
746
747         if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
748                 if (flags & IFF_LOWER_UP) {
749                         log_info_link(link, "carrier on");
750
751                         if (link->network->dhcp) {
752                                 r = link_acquire_conf(link);
753                                 if (r < 0) {
754                                         log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
755                                         link_enter_failed(link);
756                                         return r;
757                                 }
758                         }
759                 } else {
760                         log_info_link(link, "carrier off");
761
762                         if (link->network->dhcp) {
763                                 r = sd_dhcp_client_stop(link->dhcp_client);
764                                 if (r < 0) {
765                                         log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
766                                         link_enter_failed(link);
767                                         return r;
768                                 }
769                         }
770                 }
771         }
772
773         log_debug_link(link,
774                        "link status updated: %#.8x -> %#.8x", link->flags, flags);
775
776         link->flags = flags;
777
778         return 0;
779 }
780
781 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
782         Link *link = userdata;
783         int r;
784
785         assert(link);
786
787         if (link->state == LINK_STATE_FAILED)
788                 return 1;
789
790         r = sd_rtnl_message_get_errno(m);
791         if (r < 0) {
792                 log_struct_link(LOG_ERR, link,
793                                 "MESSAGE=%s: could not bring up interface: %s",
794                                 link->ifname, strerror(-r),
795                                 "ERRNO=%d", -r,
796                                 NULL);
797                 link_enter_failed(link);
798                 return 1;
799         }
800
801         link_update_flags(link, link->flags | IFF_UP);
802
803         return 1;
804 }
805
806 static int link_up(Link *link) {
807         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
808         int r;
809
810         assert(link);
811         assert(link->manager);
812         assert(link->manager->rtnl);
813
814         log_debug_link(link, "bringing link up");
815
816         r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
817                                      RTM_SETLINK, link->ifindex);
818         if (r < 0) {
819                 log_error_link(link, "Could not allocate RTM_SETLINK message");
820                 return r;
821         }
822
823         r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
824         if (r < 0) {
825                 log_error_link(link, "Could not set link flags: %s", strerror(-r));
826                 return r;
827         }
828
829         r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
830         if (r < 0) {
831                 log_error_link(link,
832                                "Could not send rtnetlink message: %s", strerror(-r));
833                 return r;
834         }
835
836         return 0;
837 }
838
839 static int link_enslaved(Link *link) {
840         int r;
841
842         assert(link);
843         assert(link->state == LINK_STATE_ENSLAVING);
844         assert(link->network);
845
846         r = link_up(link);
847         if (r < 0) {
848                 link_enter_failed(link);
849                 return r;
850         }
851
852         if (!link->network->dhcp)
853                 return link_enter_set_addresses(link);
854
855         return 0;
856 }
857
858 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
859         Link *link = userdata;
860         int r;
861
862         assert(link);
863         assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
864         assert(link->network);
865
866         link->enslaving --;
867
868         if (link->state == LINK_STATE_FAILED)
869                 return 1;
870
871         r = sd_rtnl_message_get_errno(m);
872         if (r < 0) {
873                 log_struct_link(LOG_ERR, link,
874                                 "MESSAGE=%s: could not enslave: %s",
875                                 link->ifname, strerror(-r),
876                                 "ERRNO=%d", -r,
877                                 NULL);
878                 link_enter_failed(link);
879                 return 1;
880         }
881
882         log_debug_link(link, "enslaved");
883
884         if (link->enslaving == 0)
885                 link_enslaved(link);
886
887         return 1;
888 }
889
890 static int link_enter_enslave(Link *link) {
891         NetDev *vlan;
892         Iterator i;
893         int r;
894
895         assert(link);
896         assert(link->network);
897         assert(link->state == _LINK_STATE_INVALID);
898
899         link->state = LINK_STATE_ENSLAVING;
900
901         if (!link->network->bridge && !link->network->bond &&
902             hashmap_isempty(link->network->vlans))
903                 return link_enslaved(link);
904
905         if (link->network->bridge) {
906                 log_struct_link(LOG_DEBUG, link,
907                                 "MESSAGE=%s: enslaving by '%s'",
908                                 link->ifname, link->network->bridge->name,
909                                 NETDEV(link->network->bridge),
910                                 NULL);
911
912                 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
913                 if (r < 0) {
914                         log_struct_link(LOG_WARNING, link,
915                                         "MESSAGE=%s: could not enslave by '%s': %s",
916                                         link->ifname, link->network->bridge->name, strerror(-r),
917                                         NETDEV(link->network->bridge),
918                                         NULL);
919                         link_enter_failed(link);
920                         return r;
921                 }
922
923                 link->enslaving ++;
924         }
925
926         HASHMAP_FOREACH(vlan, link->network->vlans, i) {
927                 log_struct_link(LOG_DEBUG, link,
928                                 "MESSAGE=%s: enslaving by '%s'",
929                                 link->ifname, vlan->name, NETDEV(vlan), NULL);
930
931                 r = netdev_enslave(vlan, link, &enslave_handler);
932                 if (r < 0) {
933                         log_struct_link(LOG_WARNING, link,
934                                         "MESSAGE=%s: could not enslave by '%s': %s",
935                                         link->ifname, vlan->name, strerror(-r),
936                                         NETDEV(vlan), NULL);
937                         link_enter_failed(link);
938                         return r;
939                 }
940
941                 link->enslaving ++;
942         }
943
944         return 0;
945 }
946
947 static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
948                                 void *userdata) {
949         Link *link = userdata;
950         int r;
951
952         assert(link);
953
954         if (link->state == LINK_STATE_FAILED)
955                 return 1;
956
957         r = sd_rtnl_message_get_errno(m);
958         if (r < 0) {
959                 log_struct_link(LOG_ERR, link,
960                                 "MESSAGE=%s: could not get state: %s",
961                                 link->ifname, strerror(-r),
962                                 "ERRNO=%d", -r,
963                                 NULL);
964                 link_enter_failed(link);
965                 return 1;
966         }
967
968         log_debug_link(link, "got link state");
969
970         link_update(link, m);
971
972         return 1;
973 }
974
975 static int link_getlink(Link *link) {
976         _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
977         int r;
978
979         assert(link);
980         assert(link->manager);
981         assert(link->manager->rtnl);
982
983         log_debug_link(link, "requesting link status");
984
985         r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
986                                      RTM_GETLINK, link->ifindex);
987         if (r < 0) {
988                 log_error_link(link, "Could not allocate RTM_GETLINK message");
989                 return r;
990         }
991
992         r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
993                                link, 0, NULL);
994         if (r < 0) {
995                 log_error_link(link,
996                                "Could not send rtnetlink message: %s", strerror(-r));
997                 return r;
998         }
999
1000         return 0;
1001 }
1002
1003 int link_configure(Link *link) {
1004         int r;
1005
1006         assert(link);
1007         assert(link->network);
1008         assert(link->state == _LINK_STATE_INVALID);
1009
1010         r = link_getlink(link);
1011         if (r < 0) {
1012                 link_enter_failed(link);
1013                 return r;
1014         }
1015
1016         return link_enter_enslave(link);
1017 }
1018
1019 int link_update(Link *link, sd_rtnl_message *m) {
1020         unsigned flags;
1021         void *data;
1022         uint16_t type;
1023         int r;
1024
1025         assert(link);
1026         assert(m);
1027
1028         if (link->state == LINK_STATE_FAILED)
1029                 return 0;
1030
1031         r = sd_rtnl_message_link_get_flags(m, &flags);
1032         if (r < 0) {
1033                 log_warning_link(link, "Could not get link flags");
1034                 return r;
1035         }
1036
1037         while (sd_rtnl_message_read(m, &type, &data) > 0) {
1038                 if (type == IFLA_MTU && link->network->dhcp &&
1039                     link->network->dhcp_mtu && !link->original_mtu) {
1040                         link->original_mtu = *(uint16_t *) data;
1041                         log_debug_link(link, "saved original MTU: %" PRIu16,
1042                                        link->original_mtu);
1043                 }
1044         }
1045
1046         return link_update_flags(link, flags);
1047 }