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;
39 assert(manager->links);
47 link->manager = manager;
48 link->state = _LINK_STATE_INVALID;
50 link->ifindex = udev_device_get_ifindex(device);
51 if (link->ifindex <= 0)
54 mac = udev_device_get_sysattr_value(device, "address");
56 mac_addr = ether_aton(mac);
58 memcpy(&link->mac, mac_addr, sizeof(struct ether_addr));
61 ifname = udev_device_get_sysname(device);
62 link->ifname = strdup(ifname);
64 r = hashmap_put(manager->links, &link->ifindex, link);
74 void link_free(Link *link) {
78 assert(link->manager);
80 sd_dhcp_client_free(link->dhcp_client);
81 sd_dhcp_lease_unref(link->dhcp_lease);
83 hashmap_remove(link->manager->links, &link->ifindex);
90 int link_get(Manager *m, int ifindex, Link **ret) {
100 link = hashmap_get(m->links, &ifindex_64);
109 int link_add(Manager *m, struct udev_device *device, Link **ret) {
117 r = link_new(m, device, &link);
123 r = network_get(m, device, &network);
125 return r == -ENOENT ? 0 : r;
127 r = network_apply(m, network, link);
134 static int link_enter_configured(Link *link) {
136 assert(link->state == LINK_STATE_SETTING_ROUTES);
138 log_info_link(link, "link configured");
140 link->state = LINK_STATE_CONFIGURED;
145 static void link_enter_failed(Link *link) {
148 log_warning_link(link, "failed");
150 link->state = LINK_STATE_FAILED;
153 static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
154 Link *link = userdata;
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);
162 link->route_messages --;
164 if (link->state == LINK_STATE_FAILED)
167 r = sd_rtnl_message_get_errno(m);
168 if (r < 0 && r != -EEXIST)
169 log_struct_link(LOG_WARNING, link,
170 "MESSAGE=%s: could not set route: %s",
171 link->ifname, strerror(-r),
175 /* we might have received an old reply after moving back to SETTING_ADDRESSES,
177 if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
178 log_debug_link(link, "routes set");
179 link_enter_configured(link);
185 static int link_enter_set_routes(Link *link) {
190 assert(link->network);
191 assert(link->state == LINK_STATE_SETTING_ADDRESSES);
193 link->state = LINK_STATE_SETTING_ROUTES;
195 if (!link->network->static_routes && !link->dhcp_lease)
196 return link_enter_configured(link);
198 log_debug_link(link, "setting routes");
200 LIST_FOREACH(static_routes, rt, link->network->static_routes) {
201 r = route_configure(rt, link, &route_handler);
203 log_warning_link(link,
204 "could not set routes: %s", strerror(-r));
205 link_enter_failed(link);
209 link->route_messages ++;
212 if (link->dhcp_lease) {
213 _cleanup_route_free_ Route *route = NULL;
214 struct in_addr gateway;
216 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
218 log_warning_link(link, "DHCP error: no router: %s",
223 r = route_new_dynamic(&route);
225 log_error_link(link, "Could not allocate route: %s",
230 route->family = AF_INET;
231 route->in_addr.in = gateway;
233 r = route_configure(route, link, &route_handler);
235 log_warning_link(link,
236 "could not set routes: %s", strerror(-r));
237 link_enter_failed(link);
241 link->route_messages ++;
247 static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
248 Link *link = userdata;
253 assert(link->ifname);
254 assert(link->addr_messages > 0);
255 assert(link->state == LINK_STATE_SETTING_ADDRESSES || link->state == LINK_STATE_FAILED);
257 link->addr_messages --;
259 if (link->state == LINK_STATE_FAILED)
262 r = sd_rtnl_message_get_errno(m);
263 if (r < 0 && r != -EEXIST)
264 log_struct_link(LOG_WARNING, link,
265 "MESSAGE=%s: could not set address: %s",
266 link->ifname, strerror(-r),
270 if (link->addr_messages == 0) {
271 log_debug_link(link, "addresses set");
272 link_enter_set_routes(link);
278 static int link_enter_set_addresses(Link *link) {
283 assert(link->network);
284 assert(link->state != _LINK_STATE_INVALID);
286 link->state = LINK_STATE_SETTING_ADDRESSES;
288 if (!link->network->static_addresses && !link->dhcp_lease)
289 return link_enter_set_routes(link);
291 log_debug_link(link, "setting addresses");
293 LIST_FOREACH(static_addresses, ad, link->network->static_addresses) {
294 r = address_configure(ad, link, &address_handler);
296 log_warning_link(link,
297 "could not set addresses: %s", strerror(-r));
298 link_enter_failed(link);
302 link->addr_messages ++;
305 if (link->dhcp_lease) {
306 _cleanup_address_free_ Address *address = NULL;
308 struct in_addr netmask;
311 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
313 log_warning_link(link, "DHCP error: no address: %s",
318 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
320 log_warning_link(link, "DHCP error: no netmask: %s",
325 prefixlen = net_netmask_to_prefixlen(&netmask);
327 r = address_new_dynamic(&address);
329 log_error_link(link, "Could not allocate address: %s",
334 address->family = AF_INET;
335 address->in_addr.in = addr;
336 address->prefixlen = prefixlen;
337 address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
339 r = address_configure(address, link, &address_handler);
341 log_warning_link(link,
342 "could not set addresses: %s", strerror(-r));
343 link_enter_failed(link);
347 link->addr_messages ++;
353 static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
354 Link *link = userdata;
359 assert(link->ifname);
361 if (link->state == LINK_STATE_FAILED)
364 r = sd_rtnl_message_get_errno(m);
365 if (r < 0 && r != -ENOENT)
366 log_struct_link(LOG_WARNING, link,
367 "MESSAGE=%s: could not drop address: %s",
368 link->ifname, strerror(-r),
375 static int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
378 r = sd_bus_message_get_errno(m);
380 log_warning("Could not set hostname: %s", strerror(-r));
385 static int set_hostname(sd_bus *bus, const char *hostname) {
386 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
391 log_debug("Setting transient hostname: '%s'", hostname);
393 if (!bus) { /* TODO: replace by assert when we can rely on kdbus */
394 log_info("Not connected to system bus, ignoring transient hostname.");
398 r = sd_bus_message_new_method_call(
401 "org.freedesktop.hostname1",
402 "/org/freedesktop/hostname1",
403 "org.freedesktop.hostname1",
408 r = sd_bus_message_append(m, "sb", hostname, false);
412 r = sd_bus_call_async(bus, m, set_hostname_handler, NULL, 0, NULL);
414 log_error("Could not set transient hostname: %s", strerror(-r));
419 static int set_mtu_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
420 Link *link = userdata;
425 assert(link->ifname);
427 if (link->state == LINK_STATE_FAILED)
430 r = sd_rtnl_message_get_errno(m);
432 log_struct_link(LOG_WARNING, link,
433 "MESSAGE=%s: could not set MTU: %s",
434 link->ifname, strerror(-r),
441 static int link_set_mtu(Link *link, uint32_t mtu) {
442 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
446 assert(link->manager);
447 assert(link->manager->rtnl);
449 log_debug_link(link, "setting MTU: %" PRIu32, mtu);
451 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
452 RTM_SETLINK, link->ifindex);
454 log_error_link(link, "Could not allocate RTM_SETLINK message");
458 r = sd_rtnl_message_append_u32(req, IFLA_MTU, mtu);
460 log_error_link(link, "Could not append MTU: %s", strerror(-r));
464 r = sd_rtnl_call_async(link->manager->rtnl, req, set_mtu_handler, link, 0, NULL);
467 "Could not send rtnetlink message: %s", strerror(-r));
474 static int dhcp_lease_lost(Link *link) {
475 _cleanup_address_free_ Address *address = NULL;
477 struct in_addr netmask;
482 assert(link->dhcp_lease);
484 log_warning_link(link, "DHCP lease lost");
486 r = address_new_dynamic(&address);
488 sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
489 sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
490 prefixlen = net_netmask_to_prefixlen(&netmask);
492 address->family = AF_INET;
493 address->in_addr.in = addr;
494 address->prefixlen = prefixlen;
496 address_drop(address, link, address_drop_handler);
499 if (link->network->dhcp_mtu) {
502 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
503 if (r >= 0 && link->original_mtu != mtu) {
504 r = link_set_mtu(link, link->original_mtu);
506 log_warning_link(link, "DHCP error: could not reset MTU");
507 link_enter_failed(link);
513 if (link->network->dhcp_hostname) {
514 const char *hostname = NULL;
516 r = sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
517 if (r >= 0 && hostname) {
518 r = set_hostname(link->manager->bus, "");
520 log_error("Failed to reset transient hostname");
524 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
529 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
530 sd_dhcp_lease *lease;
531 struct in_addr address;
532 struct in_addr netmask;
533 struct in_addr gateway;
535 struct in_addr *nameservers;
536 size_t nameservers_size;
542 r = sd_dhcp_client_get_lease(client, &lease);
544 log_warning_link(link, "DHCP error: no lease: %s",
549 r = sd_dhcp_lease_get_address(lease, &address);
551 log_warning_link(link, "DHCP error: no address: %s",
556 r = sd_dhcp_lease_get_netmask(lease, &netmask);
558 log_warning_link(link, "DHCP error: no netmask: %s",
563 prefixlen = net_netmask_to_prefixlen(&netmask);
565 r = sd_dhcp_lease_get_router(lease, &gateway);
567 log_warning_link(link, "DHCP error: no router: %s",
572 log_struct_link(LOG_INFO, link,
573 "MESSAGE=%s: DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
575 ADDRESS_FMT_VAL(address),
577 ADDRESS_FMT_VAL(gateway),
578 "ADDRESS=%u.%u.%u.%u",
579 ADDRESS_FMT_VAL(address),
582 "GATEWAY=%u.%u.%u.%u",
583 ADDRESS_FMT_VAL(gateway),
586 link->dhcp_lease = lease;
588 if (link->network->dhcp_dns) {
589 r = sd_dhcp_lease_get_dns(lease, &nameservers, &nameservers_size);
591 r = manager_update_resolv_conf(link->manager);
593 log_error("Failed to update resolv.conf");
597 if (link->network->dhcp_mtu) {
600 r = sd_dhcp_lease_get_mtu(lease, &mtu);
602 r = link_set_mtu(link, mtu);
604 log_error_link(link, "Failed to set MTU "
609 if (link->network->dhcp_hostname) {
610 const char *hostname;
612 r = sd_dhcp_lease_get_hostname(lease, &hostname);
614 r = set_hostname(link->manager->bus, hostname);
616 log_error("Failed to set transient hostname "
617 "to '%s'", hostname);
621 link_enter_set_addresses(link);
626 static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) {
627 Link *link = userdata;
631 assert(link->network);
632 assert(link->manager);
634 if (link->state == LINK_STATE_FAILED)
638 case DHCP_EVENT_NO_LEASE:
639 log_debug_link(link, "IP address in use.");
641 case DHCP_EVENT_EXPIRED:
642 case DHCP_EVENT_STOP:
643 case DHCP_EVENT_IP_CHANGE:
644 if (link->network->dhcp_critical) {
645 log_error_link(link, "DHCPv4 connection considered system critical, "
646 "ignoring request to reconfigure it.");
650 if (link->dhcp_lease) {
651 r = dhcp_lease_lost(link);
653 link_enter_failed(link);
658 if (event == DHCP_EVENT_IP_CHANGE) {
659 r = dhcp_lease_acquired(client, link);
661 link_enter_failed(link);
667 case DHCP_EVENT_IP_ACQUIRE:
668 r = dhcp_lease_acquired(client, link);
670 link_enter_failed(link);
676 log_warning_link(link, "DHCP error: %s", strerror(-event));
678 log_warning_link(link, "DHCP unknown event: %d", event);
685 static int link_acquire_conf(Link *link) {
689 assert(link->network);
690 assert(link->network->dhcp);
691 assert(link->manager);
692 assert(link->manager->event);
694 if (!link->dhcp_client) {
695 r = sd_dhcp_client_new(&link->dhcp_client);
699 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
703 r = sd_dhcp_client_set_index(link->dhcp_client, link->ifindex);
707 r = sd_dhcp_client_set_mac(link->dhcp_client, &link->mac);
711 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp_handler, link);
715 if (link->network->dhcp_mtu) {
716 r = sd_dhcp_client_set_request_option(link->dhcp_client, 26);
722 log_debug_link(link, "acquiring DHCPv4 lease");
724 r = sd_dhcp_client_start(link->dhcp_client);
731 static int link_update_flags(Link *link, unsigned flags) {
735 assert(link->network);
737 if (link->state == LINK_STATE_FAILED)
740 if (link->flags == flags) {
741 log_debug_link(link, "link status unchanged: %#.8x", flags);
745 if ((link->flags & IFF_UP) != (flags & IFF_UP))
747 "link is %s", flags & IFF_UP ? "up": "down");
749 if ((link->flags & IFF_LOWER_UP) != (flags & IFF_LOWER_UP)) {
750 if (flags & IFF_LOWER_UP) {
751 log_info_link(link, "carrier on");
753 if (link->network->dhcp) {
754 r = link_acquire_conf(link);
756 log_warning_link(link, "Could not acquire DHCPv4 lease: %s", strerror(-r));
757 link_enter_failed(link);
762 log_info_link(link, "carrier off");
764 if (link->network->dhcp) {
765 r = sd_dhcp_client_stop(link->dhcp_client);
767 log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
768 link_enter_failed(link);
776 "link status updated: %#.8x -> %#.8x", link->flags, flags);
783 static int link_up_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
784 Link *link = userdata;
789 if (link->state == LINK_STATE_FAILED)
792 r = sd_rtnl_message_get_errno(m);
794 log_struct_link(LOG_ERR, link,
795 "MESSAGE=%s: could not bring up interface: %s",
796 link->ifname, strerror(-r),
799 link_enter_failed(link);
803 link_update_flags(link, link->flags | IFF_UP);
808 static int link_up(Link *link) {
809 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
813 assert(link->manager);
814 assert(link->manager->rtnl);
816 log_debug_link(link, "bringing link up");
818 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
819 RTM_SETLINK, link->ifindex);
821 log_error_link(link, "Could not allocate RTM_SETLINK message");
825 r = sd_rtnl_message_link_set_flags(req, IFF_UP, IFF_UP);
827 log_error_link(link, "Could not set link flags: %s", strerror(-r));
831 r = sd_rtnl_call_async(link->manager->rtnl, req, link_up_handler, link, 0, NULL);
834 "Could not send rtnetlink message: %s", strerror(-r));
841 static int link_enslaved(Link *link) {
845 assert(link->state == LINK_STATE_ENSLAVING);
846 assert(link->network);
850 link_enter_failed(link);
854 if (!link->network->dhcp)
855 return link_enter_set_addresses(link);
860 static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
861 Link *link = userdata;
865 assert(link->state == LINK_STATE_ENSLAVING || link->state == LINK_STATE_FAILED);
866 assert(link->network);
870 if (link->state == LINK_STATE_FAILED)
873 r = sd_rtnl_message_get_errno(m);
875 log_struct_link(LOG_ERR, link,
876 "MESSAGE=%s: could not enslave: %s",
877 link->ifname, strerror(-r),
880 link_enter_failed(link);
884 log_debug_link(link, "enslaved");
886 if (link->enslaving == 0)
892 static int link_enter_enslave(Link *link) {
898 assert(link->network);
899 assert(link->state == _LINK_STATE_INVALID);
901 link->state = LINK_STATE_ENSLAVING;
903 if (!link->network->bridge && !link->network->bond &&
904 hashmap_isempty(link->network->vlans))
905 return link_enslaved(link);
907 if (link->network->bridge) {
908 log_struct_link(LOG_DEBUG, link,
909 "MESSAGE=%s: enslaving by '%s'",
910 link->ifname, link->network->bridge->name,
911 NETDEV(link->network->bridge),
914 r = netdev_enslave(link->network->bridge, link, &enslave_handler);
916 log_struct_link(LOG_WARNING, link,
917 "MESSAGE=%s: could not enslave by '%s': %s",
918 link->ifname, link->network->bridge->name, strerror(-r),
919 NETDEV(link->network->bridge),
921 link_enter_failed(link);
928 HASHMAP_FOREACH(vlan, link->network->vlans, i) {
929 log_struct_link(LOG_DEBUG, link,
930 "MESSAGE=%s: enslaving by '%s'",
931 link->ifname, vlan->name, NETDEV(vlan), NULL);
933 r = netdev_enslave(vlan, link, &enslave_handler);
935 log_struct_link(LOG_WARNING, link,
936 "MESSAGE=%s: could not enslave by '%s': %s",
937 link->ifname, vlan->name, strerror(-r),
939 link_enter_failed(link);
949 static int link_getlink_handler(sd_rtnl *rtnl, sd_rtnl_message *m,
951 Link *link = userdata;
956 if (link->state == LINK_STATE_FAILED)
959 r = sd_rtnl_message_get_errno(m);
961 log_struct_link(LOG_ERR, link,
962 "MESSAGE=%s: could not get state: %s",
963 link->ifname, strerror(-r),
966 link_enter_failed(link);
970 log_debug_link(link, "got link state");
972 link_update(link, m);
977 static int link_getlink(Link *link) {
978 _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
982 assert(link->manager);
983 assert(link->manager->rtnl);
985 log_debug_link(link, "requesting link status");
987 r = sd_rtnl_message_new_link(link->manager->rtnl, &req,
988 RTM_GETLINK, link->ifindex);
990 log_error_link(link, "Could not allocate RTM_GETLINK message");
994 r = sd_rtnl_call_async(link->manager->rtnl, req, link_getlink_handler,
998 "Could not send rtnetlink message: %s", strerror(-r));
1005 int link_configure(Link *link) {
1009 assert(link->network);
1010 assert(link->state == _LINK_STATE_INVALID);
1012 r = link_getlink(link);
1014 link_enter_failed(link);
1018 return link_enter_enslave(link);
1021 int link_update(Link *link, sd_rtnl_message *m) {
1030 if (link->state == LINK_STATE_FAILED)
1033 r = sd_rtnl_message_link_get_flags(m, &flags);
1035 log_warning_link(link, "Could not get link flags");
1039 while (sd_rtnl_message_read(m, &type, &data) > 0) {
1040 if (type == IFLA_MTU && link->network->dhcp &&
1041 link->network->dhcp_mtu && !link->original_mtu) {
1042 link->original_mtu = *(uint16_t *) data;
1043 log_debug_link(link, "saved original MTU: %" PRIu16,
1044 link->original_mtu);
1048 return link_update_flags(link, flags);