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