]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
sd-dhcp-client: refactor DNS support
[thirdparty/systemd.git] / src / network / networkd-link.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <netinet/ether.h>
23 #include <linux/if.h>
24
25 #include "networkd.h"
26 #include "libudev-private.h"
27 #include "util.h"
28 #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 }