1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <netinet/ether.h>
26 #include "libudev-private.h"
31 int link_new(Manager *manager, struct udev_device *device, Link **ret) {
32 _cleanup_link_free_ Link *link = NULL;
34 struct ether_addr *mac_addr;
45 link->manager = manager;
46 link->state = _LINK_STATE_INVALID;
48 link->ifindex = udev_device_get_ifindex(device);
49 if (link->ifindex <= 0)
52 mac = udev_device_get_sysattr_value(device, "address");
54 mac_addr = ether_aton(mac);
56 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
59 ifname = udev_device_get_sysname(device);
60 link->ifname = strdup(ifname);
62 r = hashmap_put(manager->links, &link->ifindex, link);
72 void link_free(Link *link) {
76 assert(link->manager);
78 sd_dhcp_client_free(link->dhcp_client);
79 sd_dhcp_lease_unref(link->dhcp_lease);
81 hashmap_remove(link->manager->links, &link->ifindex);
88 int link_get(Manager *m, int ifindex, Link **ret) {
98 link = hashmap_get(m->links, &ifindex_64);
107 int link_add(Manager *m, struct udev_device *device, Link **ret) {
115 r = link_new(m, device, &link);
121 r = network_get(m, device, &network);
123 return r == -ENOENT ? 0 : r;
125 r = network_apply(m, network, link);
132 static int link_enter_configured(Link *link) {
134 assert(link->state == LINK_STATE_SETTING_ROUTES);
136 log_info_link(link, "link configured");
138 link->state = LINK_STATE_CONFIGURED;
143 static void link_enter_failed(Link *link) {
146 log_warning_link(link, "failed");
148 link->state = LINK_STATE_FAILED;
151 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
152 Link *link = userdata;
155 assert(link->route_messages > 0);
156 assert(link->state == LINK_STATE_SETTING_ADDRESSES ||
157 link->state == LINK_STATE_SETTING_ROUTES ||
158 link->state == LINK_STATE_FAILED);
160 link->route_messages --;
162 if (link->state == LINK_STATE_FAILED)
165 r = sd_rtnl_message_get_errno(m);
166 if (r < 0 && r != -EEXIST)
167 log_struct_link(LOG_WARNING, link,
168 "MESSAGE=%s: could not set route: %s",
169 link->ifname, strerror(-r),
173 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
175 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
176 log_debug_link(link, "routes set");
177 link_enter_configured(link);
183 static int link_enter_set_routes(Link *link) {
188 assert(link->network);
189 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
191 link->state = LINK_STATE_SETTING_ROUTES;
193 if (!link->network->static_routes && !link->dhcp_lease)
194 return link_enter_configured(link);
196 log_debug_link(link, "setting routes");
198 LIST_FOREACH(static_routes, rt, link->network->static_routes) {
199 r = route_configure(rt, link, &route_handler);
201 log_warning_link(link,
202 "could not set routes: %s", strerror(-r));
203 link_enter_failed(link);
207 link->route_messages ++;
210 if (link->dhcp_lease) {
211 _cleanup_route_free_ Route *route = NULL;
212 struct in_addr gateway;
214 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
216 log_warning_link(link, "DHCP error: no router: %s",
221 r = route_new_dynamic(&route);
223 log_error_link(link, "Could not allocate route: %s",
228 route->family = AF_INET;
229 route->in_addr.in = gateway;
231 r = route_configure(route, link, &route_handler);
233 log_warning_link(link,
234 "could not set routes: %s", strerror(-r));
235 link_enter_failed(link);
239 link->route_messages ++;
245 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
246 Link *link = userdata;
251 assert(link->ifname);
252 assert(link->addr_messages > 0);
253 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
255 link->addr_messages --;
257 if (link->state == LINK_STATE_FAILED)
260 r = sd_rtnl_message_get_errno(m);
261 if (r < 0 && r != -EEXIST)
262 log_struct_link(LOG_WARNING, link,
263 "MESSAGE=%s: could not set address: %s",
264 link->ifname, strerror(-r),
268 if (link->addr_messages == 0) {
269 log_debug_link(link, "addresses set");
270 link_enter_set_routes(link);
276 static int link_enter_set_addresses(Link *link) {
281 assert(link->network);
282 assert(link->state != _LINK_STATE_INVALID);
284 link->state = LINK_STATE_SETTING_ADDRESSES;
286 if (!link->network->static_addresses && !link->dhcp_lease)
287 return link_enter_set_routes(link);
289 log_debug_link(link, "setting addresses");
291 LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
292 r = address_configure(ad, link, &address_handler);
294 log_warning_link(link,
295 "could not set addresses: %s", strerror(-r));
296 link_enter_failed(link);
300 link->addr_messages ++;
303 if (link->dhcp_lease) {
304 _cleanup_address_free_ Address *address = NULL;
306 struct in_addr netmask;
309 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
311 log_warning_link(link, "DHCP error: no address: %s",
316 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
318 log_warning_link(link, "DHCP error: no netmask: %s",
323 prefixlen = net_netmask_to_prefixlen(&netmask);
325 r = address_new_dynamic(&address);
327 log_error_link(link, "Could not allocate address: %s",
332 address->family = AF_INET;
333 address->in_addr.in = addr;
334 address->prefixlen = prefixlen;
335 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
337 r = address_configure(address, link, &address_handler);
339 log_warning_link(link,
340 "could not set addresses: %s", strerror(-r));
341 link_enter_failed(link);
345 link->addr_messages ++;
351 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
352 Link *link = userdata;
357 assert(link->ifname);
359 if (link->state == LINK_STATE_FAILED)
362 r = sd_rtnl_message_get_errno(m);
363 if (r < 0 && r != -ENOENT)
364 log_struct_link(LOG_WARNING, link,
365 "MESSAGE=%s: could not drop address: %s",
366 link->ifname, strerror(-r),
373 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
376 r = sd_bus_message_get_errno(m);
378 log_warning("Could not set hostname: %s", strerror(-r));
383 static int set_hostname(sd_bus *bus, const char *hostname) {
384 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
389 log_debug("Setting transient hostname: '%s'", hostname);
391 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
392 log_info("Not connected to system bus, ignoring transient hostname.");
396 r = sd_bus_message_new_method_call(
399 "org.freedesktop.hostname1",
400 "/org/freedesktop/hostname1",
401 "org.freedesktop.hostname1",
406 r = sd_bus_message_append(m, "sb", hostname, false);
410 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
412 log_error("Could not set transient hostname: %s", strerror(-r));
417 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
418 Link *link = userdata;
423 assert(link->ifname);
425 if (link->state == LINK_STATE_FAILED)
428 r = sd_rtnl_message_get_errno(m);
430 log_struct_link(LOG_WARNING, link,
431 "MESSAGE=%s: could not set MTU: %s",
432 link->ifname, strerror(-r),
439 static int link_set_mtu(Link *link, uint32_t mtu) {
440 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
444 assert(link->manager);
445 assert(link->manager->rtnl);
447 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
449 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
450 RTM_SETLINK, link->ifindex);
452 log_error_link(link, "Could not allocate RTM_SETLINK message");
456 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
458 log_error_link(link, "Could not append MTU: %s", strerror(-r));
462 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
465 "Could not send rtnetlink message: %s", strerror(-r));
472 static int dhcp_lease_lost(Link *link) {
473 _cleanup_address_free_ Address *address = NULL;
475 struct in_addr netmask;
480 assert(link->dhcp_lease);
482 log_warning_link(link, "DHCP lease lost");
484 r = address_new_dynamic(&address);
486 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
487 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
488 prefixlen = net_netmask_to_prefixlen(&netmask);
490 address->family = AF_INET;
491 address->in_addr.in = addr;
492 address->prefixlen = prefixlen;
494 address_drop(address, link, address_drop_handler);
497 if (link->network->dhcp_mtu) {
500 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
501 if (r >= 0 && link->original_mtu != mtu) {
502 r = link_set_mtu(link, link->original_mtu);
504 log_warning_link(link, "DHCP error: could not reset MTU");
505 link_enter_failed(link);
511 if (link->network->dhcp_hostname) {
512 const char *hostname = NULL;
514 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
515 if (r >= 0 && hostname) {
516 r = set_hostname(link->manager->bus, "");
518 log_error("Failed to reset transient hostname");
522 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
527 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
528 sd_dhcp_lease *lease;
529 struct in_addr address;
530 struct in_addr netmask;
531 struct in_addr gateway;
533 struct in_addr *nameservers;
534 size_t nameservers_size;
540 r = sd_dhcp_client_get_lease(client, &lease);
542 log_warning_link(link, "DHCP error: no lease: %s",
547 r = sd_dhcp_lease_get_address(lease, &address);
549 log_warning_link(link, "DHCP error: no address: %s",
554 r = sd_dhcp_lease_get_netmask(lease, &netmask);
556 log_warning_link(link, "DHCP error: no netmask: %s",
561 prefixlen = net_netmask_to_prefixlen(&netmask);
563 r = sd_dhcp_lease_get_router(lease, &gateway);
565 log_warning_link(link, "DHCP error: no router: %s",
570 log_struct_link(LOG_INFO, link,
571 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
573 ADDRESS_FMT_VAL(address),
575 ADDRESS_FMT_VAL(gateway),
576 "ADDRESS=%u.%u.%u.%u",
577 ADDRESS_FMT_VAL(address),
580 "GATEWAY=%u.%u.%u.%u",
581 ADDRESS_FMT_VAL(gateway),
584 link->dhcp_lease = lease;
586 if (link->network->dhcp_dns) {
587 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
589 r = manager_update_resolv_conf(link->manager);
591 log_error("Failed to update resolv.conf");
595 if (link->network->dhcp_mtu) {
598 r = sd_dhcp_lease_get_mtu(lease, &mtu);
600 r = link_set_mtu(link, mtu);
602 log_error_link(link, "Failed to set MTU "
607 if (link->network->dhcp_hostname) {
608 const char *hostname;
610 r = sd_dhcp_lease_get_hostname(lease, &hostname);
612 r = set_hostname(link->manager->bus, hostname);
614 log_error("Failed to set transient hostname "
615 "to '%s'", hostname);
619 link_enter_set_addresses(link);
624 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
625 Link *link = userdata;
629 assert(link->network);
630 assert(link->manager);
632 if (link->state == LINK_STATE_FAILED)
636 case DHCP_EVENT_NO_LEASE:
637 log_debug_link(link, "IP address in use.");
639 case DHCP_EVENT_EXPIRED:
640 case DHCP_EVENT_STOP:
641 case DHCP_EVENT_IP_CHANGE:
642 if (link->network->dhcp_critical) {
643 log_error_link(link, "DHCPv4 connection considered system critical, "
644 "ignoring request to reconfigure it.");
648 if (link->dhcp_lease) {
649 r = dhcp_lease_lost(link);
651 link_enter_failed(link);
656 if (event == DHCP_EVENT_IP_CHANGE) {
657 r = dhcp_lease_acquired(client, link);
659 link_enter_failed(link);
665 case DHCP_EVENT_IP_ACQUIRE:
666 r = dhcp_lease_acquired(client, link);
668 link_enter_failed(link);
674 log_warning_link(link, "DHCP error: %s", strerror(-event));
676 log_warning_link(link, "DHCP unknown event: %d", event);
683 static int link_acquire_conf(Link *link) {
687 assert(link->network);
688 assert(link->network->dhcp);
689 assert(link->manager);
690 assert(link->manager->event);
692 if (!link->dhcp_client) {
693 r = sd_dhcp_client_new(&link->dhcp_client);
697 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
701 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
705 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
709 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
713 if (link->network->dhcp_mtu) {
714 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
720 log_debug_link(link, "acquiring DHCPv4 lease");
722 r = sd_dhcp_client_start(link->dhcp_client);
729 static int link_update_flags(Link *link, unsigned flags) {
733 assert(link->network);
735 if (link->state == LINK_STATE_FAILED)
738 if (link->flags == flags) {
739 log_debug_link(link, "link status unchanged: %#.8x", flags);
743 if ((link->flags & IFF_UP) != (flags & IFF_UP))
745 "link is %s", flags & IFF_UP ? "up": "down");
747 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
748 if (flags & IFF_LOWER_UP) {
749 log_info_link(link, "carrier on");
751 if (link->network->dhcp) {
752 r = link_acquire_conf(link);
754 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
755 link_enter_failed(link);
760 log_info_link(link, "carrier off");
762 if (link->network->dhcp) {
763 r = sd_dhcp_client_stop(link->dhcp_client);
765 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
766 link_enter_failed(link);
774 "link status updated: %#.8x -> %#.8x", link->flags, flags);
781 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
782 Link *link = userdata;
787 if (link->state == LINK_STATE_FAILED)
790 r = sd_rtnl_message_get_errno(m);
792 log_struct_link(LOG_ERR, link,
793 "MESSAGE=%s: could not bring up interface: %s",
794 link->ifname, strerror(-r),
797 link_enter_failed(link);
801 link_update_flags(link, link->flags | IFF_UP);
806 static int link_up(Link *link) {
807 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
811 assert(link->manager);
812 assert(link->manager->rtnl);
814 log_debug_link(link, "bringing link up");
816 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
817 RTM_SETLINK, link->ifindex);
819 log_error_link(link, "Could not allocate RTM_SETLINK message");
823 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
825 log_error_link(link, "Could not set link flags: %s", strerror(-r));
829 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
832 "Could not send rtnetlink message: %s", strerror(-r));
839 static int link_enslaved(Link *link) {
843 assert(link->state == LINK_STATE_ENSLAVING);
844 assert(link->network);
848 link_enter_failed(link);
852 if (!link->network->dhcp)
853 return link_enter_set_addresses(link);
858 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
859 Link *link = userdata;
863 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
864 assert(link->network);
868 if (link->state == LINK_STATE_FAILED)
871 r = sd_rtnl_message_get_errno(m);
873 log_struct_link(LOG_ERR, link,
874 "MESSAGE=%s: could not enslave: %s",
875 link->ifname, strerror(-r),
878 link_enter_failed(link);
882 log_debug_link(link, "enslaved");
884 if (link->enslaving == 0)
890 static int link_enter_enslave(Link *link) {
896 assert(link->network);
897 assert(link->state == _LINK_STATE_INVALID);
899 link->state = LINK_STATE_ENSLAVING;
901 if (!link->network->bridge && !link->network->bond &&
902 hashmap_isempty(link->network->vlans))
903 return link_enslaved(link);
905 if (link->network->bridge) {
906 log_struct_link(LOG_DEBUG, link,
907 "MESSAGE=%s: enslaving by '%s'",
908 link->ifname, link->network->bridge->name,
909 NETDEV(link->network->bridge),
912 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
914 log_struct_link(LOG_WARNING, link,
915 "MESSAGE=%s: could not enslave by '%s': %s",
916 link->ifname, link->network->bridge->name, strerror(-r),
917 NETDEV(link->network->bridge),
919 link_enter_failed(link);
926 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
927 log_struct_link(LOG_DEBUG, link,
928 "MESSAGE=%s: enslaving by '%s'",
929 link->ifname, vlan->name, NETDEV(vlan), NULL);
931 r = netdev_enslave(vlan, link, &enslave_handler);
933 log_struct_link(LOG_WARNING, link,
934 "MESSAGE=%s: could not enslave by '%s': %s",
935 link->ifname, vlan->name, strerror(-r),
937 link_enter_failed(link);
947 static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
949 Link *link = userdata;
954 if (link->state == LINK_STATE_FAILED)
957 r = sd_rtnl_message_get_errno(m);
959 log_struct_link(LOG_ERR, link,
960 "MESSAGE=%s: could not get state: %s",
961 link->ifname, strerror(-r),
964 link_enter_failed(link);
968 log_debug_link(link, "got link state");
970 link_update(link, m);
975 static int link_getlink(Link *link) {
976 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
980 assert(link->manager);
981 assert(link->manager->rtnl);
983 log_debug_link(link, "requesting link status");
985 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
986 RTM_GETLINK, link->ifindex);
988 log_error_link(link, "Could not allocate RTM_GETLINK message");
992 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
996 "Could not send rtnetlink message: %s", strerror(-r));
1003 int link_configure(Link *link) {
1007 assert(link->network);
1008 assert(link->state == _LINK_STATE_INVALID);
1010 r = link_getlink(link);
1012 link_enter_failed(link);
1016 return link_enter_enslave(link);
1019 int link_update(Link *link, sd_rtnl_message *m) {
1028 if (link->state == LINK_STATE_FAILED)
1031 r = sd_rtnl_message_link_get_flags(m, &flags);
1033 log_warning_link(link, "Could not get link flags");
1037 while (sd_rtnl_message_read(m, &type, &data) > 0) {
1038 if (type == IFLA_MTU && link->network->dhcp &&
1039 link->network->dhcp_mtu && !link->original_mtu) {
1040 link->original_mtu = *(uint16_t *) data;
1041 log_debug_link(link, "saved original MTU: %" PRIu16,
1042 link->original_mtu);
1046 return link_update_flags(link, flags);