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