]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-link.c
sd-dhcp-client: refactor client_{free,new}
[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(hostname);
329
330 log_debug("Setting transient hostname: '%s'", hostname);
331
332 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
333 log_info("Not connected to system bus, ignoring transient hostname.");
334 return 0;
335 }
336
337 r = sd_bus_message_new_method_call(
338 bus,
339 "org.freedesktop.hostname1",
340 "/org/freedesktop/hostname1",
341 "org.freedesktop.hostname1",
342 "SetHostname",
343 &m);
344 if (r < 0)
345 return r;
346
347 r = sd_bus_message_append(m, "sb", hostname, false);
348 if (r < 0)
349 return r;
350
351 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
352 if (r < 0)
353 log_error("Could not set transient hostname: %s", strerror(-r));
354
355 return r;
356 }
357
358 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
359 Link *link = userdata;
360 int r;
361
362 assert(m);
363 assert(link);
364 assert(link->ifname);
365
366 if (link->state == LINK_STATE_FAILED)
367 return 1;
368
369 r = sd_rtnl_message_get_errno(m);
370 if (r < 0 && r != -EEXIST)
371 log_warning_link(link, "Could not set MTU: %s", strerror(-r));
372
373 return 1;
374 }
375
376 static int link_set_mtu(Link *link, uint32_t mtu) {
377 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
378 int r;
379
380 assert(link);
381 assert(link->manager);
382 assert(link->manager->rtnl);
383
384 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
385
386 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
387 if (r < 0) {
388 log_error_link(link, "Could not allocate RTM_SETLINK message");
389 return r;
390 }
391
392 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
393 if (r < 0) {
394 log_error_link(link, "Could not append MTU: %s", strerror(-r));
395 return r;
396 }
397
398 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
399 if (r < 0) {
400 log_error_link(link,
401 "Could not send rtnetlink message: %s", strerror(-r));
402 return r;
403 }
404
405 return 0;
406 }
407
408 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
409 Link *link = userdata;
410 struct in_addr address;
411 struct in_addr netmask;
412 struct in_addr gateway;
413 int prefixlen;
414 int r;
415
416 assert(link);
417 assert(link->network);
418 assert(link->manager);
419
420 if (link->state == LINK_STATE_FAILED)
421 return;
422
423 if (event < 0) {
424 log_warning_link(link, "DHCP error: %s", strerror(-event));
425 link_enter_failed(link);
426 return;
427 }
428
429 if (event == DHCP_EVENT_NO_LEASE)
430 log_debug_link(link, "IP address in use.");
431
432 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_EXPIRED ||
433 event == DHCP_EVENT_STOP) {
434 if (link->dhcp_address) {
435 address_drop(link->dhcp_address, link, address_drop_handler);
436
437 address_free(link->dhcp_address);
438 link->dhcp_address = NULL;
439 }
440
441 if (link->dhcp_route) {
442 route_free(link->dhcp_route);
443 link->dhcp_route = NULL;
444 }
445
446 if (link->network->dhcp_mtu) {
447 uint16_t mtu;
448
449 r = sd_dhcp_client_get_mtu(client, &mtu);
450 if (r >= 0 && link->original_mtu != mtu) {
451 r = link_set_mtu(link, link->original_mtu);
452 if (r < 0) {
453 log_warning_link(link, "DHCP error: could not reset MTU");
454 link_enter_failed(link);
455 return;
456 }
457 }
458 }
459
460 if (link->network->dhcp_hostname) {
461 r = set_hostname(link->manager->bus, "");
462 if (r < 0)
463 log_error("Failed to reset transient hostname");
464 }
465 }
466
467 r = sd_dhcp_client_get_address(client, &address);
468 if (r < 0) {
469 log_warning_link(link, "DHCP error: no address");
470 link_enter_failed(link);
471 return;
472 }
473
474 r = sd_dhcp_client_get_netmask(client, &netmask);
475 if (r < 0) {
476 log_warning_link(link, "DHCP error: no netmask");
477 link_enter_failed(link);
478 return;
479 }
480
481 prefixlen = sd_dhcp_client_prefixlen(&netmask);
482 if (prefixlen < 0) {
483 log_warning_link(link, "DHCP error: no prefixlen");
484 link_enter_failed(link);
485 return;
486 }
487
488 r = sd_dhcp_client_get_router(client, &gateway);
489 if (r < 0) {
490 log_warning_link(link, "DHCP error: no router");
491 link_enter_failed(link);
492 return;
493 }
494
495 if (event == DHCP_EVENT_IP_CHANGE || event == DHCP_EVENT_IP_ACQUIRE) {
496 _cleanup_address_free_ Address *addr = NULL;
497 _cleanup_route_free_ Route *rt = NULL;
498 struct in_addr *nameservers;
499 size_t nameservers_size;
500
501 log_struct_link(LOG_INFO, link,
502 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
503 link->ifname,
504 ADDRESS_FMT_VAL(address),
505 prefixlen,
506 ADDRESS_FMT_VAL(gateway),
507 "ADDRESS=%u.%u.%u.%u",
508 ADDRESS_FMT_VAL(address),
509 "PREFIXLEN=%u",
510 prefixlen,
511 "GATEWAY=%u.%u.%u.%u",
512 ADDRESS_FMT_VAL(gateway),
513 NULL);
514
515 r = address_new_dynamic(&addr);
516 if (r < 0) {
517 log_error_link(link, "Could not allocate address");
518 link_enter_failed(link);
519 return;
520 }
521
522 addr->family = AF_INET;
523 addr->in_addr.in = address;
524 addr->prefixlen = prefixlen;
525 addr->netmask = netmask;
526
527 r = route_new_dynamic(&rt);
528 if (r < 0) {
529 log_error_link(link, "Could not allocate route");
530 link_enter_failed(link);
531 return;
532 }
533
534 rt->family = AF_INET;
535 rt->in_addr.in = gateway;
536
537 link->dhcp_address = addr;
538 link->dhcp_route = rt;
539 addr = NULL;
540 rt = NULL;
541
542 if (link->network->dhcp_dns) {
543 r = sd_dhcp_client_get_dns(client, &nameservers, &nameservers_size);
544 if (r >= 0) {
545 r = manager_update_resolv_conf(link->manager);
546 if (r < 0)
547 log_error("Failed to update resolv.conf");
548 }
549 }
550
551 if (link->network->dhcp_mtu) {
552 uint16_t mtu;
553
554 r = sd_dhcp_client_get_mtu(client, &mtu);
555 if (r >= 0) {
556 r = link_set_mtu(link, mtu);
557 if (r < 0)
558 log_error_link(link, "Failed to set MTU "
559 "to %" PRIu16, mtu);
560 }
561 }
562
563 if (link->network->dhcp_hostname) {
564 const char *hostname;
565
566 r = sd_dhcp_client_get_hostname(client, &hostname);
567 if (r >= 0) {
568 r = set_hostname(link->manager->bus, hostname);
569 if (r < 0)
570 log_error("Failed to set transient hostname "
571 "to '%s'", hostname);
572 }
573 }
574
575 link_enter_set_addresses(link);
576 }
577
578 return;
579 }
580
581 static int link_acquire_conf(Link *link) {
582 int r;
583
584 assert(link);
585 assert(link->network);
586 assert(link->network->dhcp);
587 assert(link->manager);
588 assert(link->manager->event);
589
590 if (!link->dhcp) {
591 r = sd_dhcp_client_new(&link->dhcp);
592 if (r < 0)
593 return r;
594
595 r = sd_dhcp_client_attach_event(link->dhcp, NULL, 0);
596 if (r < 0)
597 return r;
598
599 r = sd_dhcp_client_set_index(link->dhcp, link->ifindex);
600 if (r < 0)
601 return r;
602
603 r = sd_dhcp_client_set_mac(link->dhcp, &link->mac);
604 if (r < 0)
605 return r;
606
607 r = sd_dhcp_client_set_callback(link->dhcp, dhcp_handler, link);
608 if (r < 0)
609 return r;
610
611 if (link->network->dhcp_mtu) {
612 r = sd_dhcp_client_set_request_option(link->dhcp, 26);
613 if (r < 0)
614 return r;
615 }
616 }
617
618 log_debug_link(link, "acquiring DHCPv4 lease");
619
620 r = sd_dhcp_client_start(link->dhcp);
621 if (r < 0)
622 return r;
623
624 return 0;
625 }
626
627 static int link_update_flags(Link *link, unsigned flags) {
628 int r;
629
630 assert(link);
631 assert(link->network);
632
633 if (link->state == LINK_STATE_FAILED)
634 return 0;
635
636 if (link->flags == flags) {
637 log_debug_link(link, "link status unchanged: %#.8x", flags);
638 return 0;
639 }
640
641 if ((link->flags & IFF_UP) != (flags & IFF_UP))
642 log_info_link(link,
643 "power %s", flags & IFF_UP ? "on": "off");
644
645 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
646 if (flags & IFF_LOWER_UP) {
647 log_info_link(link, "carrier on");
648
649 if (link->network->dhcp) {
650 r = link_acquire_conf(link);
651 if (r < 0) {
652 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
653 link_enter_failed(link);
654 return r;
655 }
656 }
657 } else {
658 log_info_link(link, "carrier off");
659
660 if (link->network->dhcp) {
661 r = sd_dhcp_client_stop(link->dhcp);
662 if (r < 0) {
663 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
664 link_enter_failed(link);
665 return r;
666 }
667 }
668 }
669 }
670
671 log_debug_link(link,
672 "link status updated: %#.8x -> %#.8x", link->flags, flags);
673
674 link->flags = flags;
675
676 return 0;
677 }
678
679 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
680 Link *link = userdata;
681 int r;
682
683 assert(link);
684
685 if (link->state == LINK_STATE_FAILED)
686 return 1;
687
688 r = sd_rtnl_message_get_errno(m);
689 if (r < 0) {
690 log_warning_link(link,
691 "could not bring up interface: %s", strerror(-r));
692 link_enter_failed(link);
693 }
694
695 link_update_flags(link, link->flags | IFF_UP);
696
697 return 1;
698 }
699
700 static int link_up(Link *link) {
701 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
702 int r;
703
704 assert(link);
705 assert(link->manager);
706 assert(link->manager->rtnl);
707
708 log_debug_link(link, "bringing link up");
709
710 r = sd_rtnl_message_link_new(RTM_SETLINK, link->ifindex, &req);
711 if (r < 0) {
712 log_error_link(link, "Could not allocate RTM_SETLINK message");
713 return r;
714 }
715
716 r = sd_rtnl_message_link_set_flags(req, IFF_UP);
717 if (r < 0) {
718 log_error_link(link, "Could not set link flags: %s", strerror(-r));
719 return r;
720 }
721
722 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
723 if (r < 0) {
724 log_error_link(link,
725 "Could not send rtnetlink message: %s", strerror(-r));
726 return r;
727 }
728
729 return 0;
730 }
731
732 static int link_bridge_joined(Link *link) {
733 int r;
734
735 assert(link);
736 assert(link->state == LINK_STATE_JOINING_BRIDGE);
737 assert(link->network);
738
739 r = link_up(link);
740 if (r < 0) {
741 link_enter_failed(link);
742 return r;
743 }
744
745 if (!link->network->dhcp)
746 return link_enter_set_addresses(link);
747
748 return 0;
749 }
750
751 static int bridge_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
752 Link *link = userdata;
753 int r;
754
755 assert(link);
756 assert(link->state == LINK_STATE_JOINING_BRIDGE || link->state == LINK_STATE_FAILED);
757 assert(link->network);
758
759 if (link->state == LINK_STATE_FAILED)
760 return 1;
761
762 r = sd_rtnl_message_get_errno(m);
763 if (r < 0) {
764 log_struct_link(LOG_ERR, link,
765 "MESSAGE=%s: could not join bridge '%s': %s",
766 link->ifname, link->network->bridge->name, strerror(-r),
767 BRIDGE(link->network->bridge),
768 NULL);
769 link_enter_failed(link);
770 return 1;
771 }
772
773 log_struct_link(LOG_DEBUG, link,
774 "MESSAGE=%s: joined bridge '%s'",
775 link->network->bridge->name,
776 BRIDGE(link->network->bridge),
777 NULL);
778
779 link_bridge_joined(link);
780
781 return 1;
782 }
783
784 static int link_enter_join_bridge(Link *link) {
785 int r;
786
787 assert(link);
788 assert(link->network);
789 assert(link->state == _LINK_STATE_INVALID);
790
791 link->state = LINK_STATE_JOINING_BRIDGE;
792
793 if (!link->network->bridge)
794 return link_bridge_joined(link);
795
796 log_struct_link(LOG_DEBUG, link,
797 "MESSAGE=%s: joining bridge '%s'",
798 link->network->bridge->name,
799 BRIDGE(link->network->bridge),
800 NULL);
801 log_debug_link(link, "joining bridge");
802
803 r = bridge_join(link->network->bridge, link, &bridge_handler);
804 if (r < 0) {
805 log_struct_link(LOG_WARNING, link,
806 "MESSAGE=%s: could not join bridge '%s': %s",
807 link->network->bridge->name, strerror(-r),
808 BRIDGE(link->network->bridge),
809 NULL);
810 link_enter_failed(link);
811 return r;
812 }
813
814 return 0;
815 }
816
817 static int link_get_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
818 Link *link = userdata;
819 int r;
820
821 assert(link);
822
823 if (link->state == LINK_STATE_FAILED)
824 return 1;
825
826 r = sd_rtnl_message_get_errno(m);
827 if (r < 0) {
828 log_warning_link(link, "could not get state: %s", strerror(-r));
829 link_enter_failed(link);
830 }
831
832 log_debug_link(link, "got link state");
833
834 link_update(link, m);
835
836 return 1;
837 }
838
839 static int link_get(Link *link) {
840 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *req = NULL;
841 int r;
842
843 assert(link);
844 assert(link->manager);
845 assert(link->manager->rtnl);
846
847 log_debug_link(link, "requesting link status");
848
849 r = sd_rtnl_message_link_new(RTM_GETLINK, link->ifindex, &req);
850 if (r < 0) {
851 log_error_link(link, "Could not allocate RTM_GETLINK message");
852 return r;
853 }
854
855 r = sd_rtnl_call_async(link->manager->rtnl, req, link_get_handler, link, 0, NULL);
856 if (r < 0) {
857 log_error_link(link,
858 "Could not send rtnetlink message: %s", strerror(-r));
859 return r;
860 }
861
862 return 0;
863 }
864
865 int link_configure(Link *link) {
866 int r;
867
868 assert(link);
869 assert(link->network);
870 assert(link->state == _LINK_STATE_INVALID);
871
872 r = link_get(link);
873 if (r < 0) {
874 link_enter_failed(link);
875 return r;
876 }
877
878 return link_enter_join_bridge(link);
879 }
880
881 int link_update(Link *link, sd_rtnl_message *m) {
882 unsigned flags;
883 void *data;
884 uint16_t type;
885 int r;
886
887 assert(link);
888 assert(m);
889
890 if (link->state == LINK_STATE_FAILED)
891 return 0;
892
893 r = sd_rtnl_message_link_get_flags(m, &flags);
894 if (r < 0) {
895 log_warning_link(link, "Could not get link flags");
896 return r;
897 }
898
899 while (sd_rtnl_message_read(m, &type, &data) > 0) {
900 if (type == IFLA_MTU && link->network->dhcp &&
901 link->network->dhcp_mtu && !link->original_mtu) {
902 link->original_mtu = *(uint16_t *) data;
903 log_debug_link(link, "saved original MTU: %" PRIu16,
904 link->original_mtu);
905 }
906 }
907
908 return link_update_flags(link, flags);
909 }