networkd-link.c revision 4faefc7ff884eae65a80e82313fd9f4bb859d6db
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek This file is part of systemd.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek Copyright 2013 Tom Gundersen <teg@jklm.no>
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek systemd is free software; you can redistribute it and/or modify it
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek under the terms of the GNU Lesser General Public License as published by
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek the Free Software Foundation; either version 2.1 of the License, or
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek (at your option) any later version.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek systemd is distributed in the hope that it will be useful, but
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek WITHOUT ANY WARRANTY; without even the implied warranty of
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek Lesser General Public License for more details.
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek You should have received a copy of the GNU Lesser General Public License
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek along with systemd; If not, see <http://www.gnu.org/licenses/>.
24882e06c135584f16f31ba8a00fecde8b7f6fadLennart Poetteringstatic int ipv4ll_address_update(Link *link, bool deprecate);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic bool ipv4ll_is_bound(sd_ipv4ll *ll);
799a8f39d8eb9ea725e85a598c0f5dbd658c8ba7Zbigniew Jędrzejewski-Szmekstatic int link_new(Manager *manager, sd_rtnl_message *message, Link **ret) {
799a8f39d8eb9ea725e85a598c0f5dbd658c8ba7Zbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_type(message, &type);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek r = sd_rtnl_message_read_string(message, IFLA_IFNAME, &ifname);
8847551bcbfa8265bae04f567bb1aadc7b480325Zbigniew Jędrzejewski-Szmek link->state = LINK_STATE_INITIALIZING;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_read_ether_addr(message, IFLA_ADDRESS, &link->mac);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug_link(link, "MAC address not found for new device, continuing without");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = asprintf(&link->state_file, "/run/systemd/netif/links/%"PRIu64,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = asprintf(&link->lease_file, "/run/systemd/netif/leases/%"PRIu64,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = hashmap_put(manager->links, &link->ifindex, link);
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmekstatic void link_free(Link *link) {
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek while ((address = link->addresses)) {
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt LIST_REMOVE(addresses, link->addresses, address);
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek while ((address = link->pool_addresses)) {
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek LIST_REMOVE(addresses, link->pool_addresses, address);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek sd_dhcp_client_unref(link->dhcp_client);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek sd_dhcp_lease_unref(link->dhcp_lease);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek sd_dhcp6_client_unref(link->dhcp6_client);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek sd_icmp6_nd_unref(link->icmp6_router_discovery);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek hashmap_remove(link->manager->links, &link->ifindex);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek if (link && (-- link->n_ref <= 0))
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmekint link_get(Manager *m, int ifindex, Link **ret) {
36d4739a68c3edafe4d145d525a26de4ef0b8e5aZbigniew Jędrzejewski-Szmek link = hashmap_get(m->links, &ifindex_64);
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek if (!link || link->state == LINK_STATE_LINGER)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek link->state = LINK_STATE_LINGER;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_debug_link(link, "link removed");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic void link_enter_unmanaged(Link *link) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_debug_link(link, "unmanaged");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek link->state = LINK_STATE_UNMANAGED;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int link_stop_clients(Link *link) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek k = sd_dhcp_client_stop(link->dhcp_client);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not stop DHCPv4 client: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek k = sd_ipv4ll_stop(link->ipv4ll);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not stop IPv4 link-local: %s", strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (link->network->dhcp_server) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek k = sd_dhcp_server_stop(link->dhcp_server);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not stop DHCPv4 server: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek assert(link->icmp6_router_discovery);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek k = sd_dhcp6_client_stop(link->dhcp6_client);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek k = sd_icmp6_nd_stop(link->icmp6_router_discovery);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not stop ICMPv6 router discovery: %s", strerror(-r));
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmekstatic void link_enter_failed(Link *link) {
8847551bcbfa8265bae04f567bb1aadc7b480325Zbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek log_warning_link(link, "failed");
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek link->state = LINK_STATE_FAILED;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic Address* link_find_dhcp_server_address(Link *link) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek /* The the first statically configured address if there is any */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek LIST_FOREACH(addresses, address, link->network->static_addresses) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (in_addr_null(address->family, &address->in_addr))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek /* If that didn't work, find a suitable address we got from the pool */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek LIST_FOREACH(addresses, address, link->pool_addresses) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int link_enter_configured(Link *link) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek assert(link->state == LINK_STATE_SETTING_ROUTES);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (link->network->dhcp_server &&
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek !sd_dhcp_server_is_running(link->dhcp_server)) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek address = link_find_dhcp_server_address(link);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Failed to find suitable address for DHCPv4 server instance.");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_debug_link(link, "offering DHCPv4 leases");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_dhcp_server_set_address(link->dhcp_server, &address->in_addr.in);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek /* offer 32 addresses starting from the address following the server address */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek pool_start.s_addr = htobe32(be32toh(address->in_addr.in.s_addr) + 1);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_dhcp_server_set_lease_pool(link->dhcp_server,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_dhcp_server_set_router(link->dhcp_server,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek &main_address->in_addr.in);
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek r = sd_dhcp_server_set_prefixlen(link->dhcp_server,
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek main_address->prefixlen);
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek r = sd_dhcp_server_start(link->dhcp_server);
8201af08fa09c2bd0f005fbe262f27e2c5bd2d86Zbigniew Jędrzejewski-Szmek log_warning_link(link, "could not start DHCPv4 server "
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_info_link(link, "link configured");
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek link->state = LINK_STATE_CONFIGURED;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek assert(link->route_messages > 0);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LINK_STATE_SETTING_ROUTES, LINK_STATE_FAILED,
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (IN_SET(LINK_STATE_FAILED, LINK_STATE_LINGER))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -EEXIST)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_struct_link(LOG_WARNING, link,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "MESSAGE=%-*s: could not set route: %s",
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek /* we might have received an old reply after moving back to SETTING_ADDRESSES,
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek if (link->route_messages == 0 && link->state == LINK_STATE_SETTING_ROUTES) {
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek log_debug_link(link, "routes set");
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmekstatic int link_set_dhcp_routes(Link *link) {
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek struct sd_dhcp_route *static_routes;
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek r = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes, &static_routes_size);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek log_warning_link(link, "DHCP error: could not get routes: %s", strerror(-r));
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek for (i = 0; i < static_routes_size; i++) {
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek _cleanup_route_free_ Route *route = NULL;
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate route: %s",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek route->in_addr.in = static_routes[i].gw_addr;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek route->dst_addr.in = static_routes[i].dst_addr;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek route->dst_prefixlen = static_routes[i].dst_prefixlen;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek route->metrics = DHCP_ROUTE_METRIC;
50a0b0717563d08c027a16a896bff8d7754eab9eZbigniew Jędrzejewski-Szmek r = route_configure(route, link, &route_handler);
50a0b0717563d08c027a16a896bff8d7754eab9eZbigniew Jędrzejewski-Szmek "could not set host route: %s", strerror(-r));
50a0b0717563d08c027a16a896bff8d7754eab9eZbigniew Jędrzejewski-Szmekstatic int link_enter_set_routes(Link *link) {
5bc891206dd8eb4e4df58f502b0184b8426caf22Zbigniew Jędrzejewski-Szmek assert(link->state == LINK_STATE_SETTING_ADDRESSES);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek link->state = LINK_STATE_SETTING_ROUTES;
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt if (!link->network->static_routes && !link->dhcp_lease &&
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek return link_enter_configured(link);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek LIST_FOREACH(routes, rt, link->network->static_routes) {
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek r = route_configure(rt, link, &route_handler);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "could not set routes: %s", strerror(-r));
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek if (link->ipv4ll && !link->dhcp_lease) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek _cleanup_route_free_ Route *route = NULL;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "IPV4LL error: no address: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate route: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek route->metrics = IPV4LL_ROUTE_METRIC;
30776485c5bc2d9c356e875f2aee874d22c393b7Zbigniew Jędrzejewski-Szmek r = route_configure(route, link, &route_handler);
30776485c5bc2d9c356e875f2aee874d22c393b7Zbigniew Jędrzejewski-Szmek "could not set routes: %s", strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_route_free_ Route *route = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_route_free_ Route *route_gw = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_warning_link(link, "DHCP error: could not get gateway: %s",
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate route: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = route_new_dynamic(&route_gw);
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate route: %s",
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek /* The dhcp netmask may mask out the gateway. Add an explicit
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek * route for the gw host so that we can route no matter the
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek * netmask or existing kernel route tables. */
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek route_gw->metrics = DHCP_ROUTE_METRIC;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = route_configure(route_gw, link, &route_handler);
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering "could not set host route: %s", strerror(-r));
1af719edc5958c01c19204fb68d6fc45c9eea85cZbigniew Jędrzejewski-Szmek route->metrics = DHCP_ROUTE_METRIC;
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering r = route_configure(route, link, &route_handler);
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering "could not set routes: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (link->route_messages == 0) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (r < 0 && r != -ESRCH)
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek log_struct_link(LOG_WARNING, link,
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek "MESSAGE=%-*s: could not drop route: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering _cleanup_link_unref_ Link *link = userdata;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek for (; m; m = sd_rtnl_message_next(m)) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_debug_link(link, "getting address failed: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = link_rtnl_process_address(rtnl, m, link->manager);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "could not process address: %s", strerror(-r));
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmekstatic int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek assert(link->addr_messages > 0);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek assert(IN_SET(link->state, LINK_STATE_SETTING_ADDRESSES,
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek LINK_STATE_FAILED, LINK_STATE_LINGER));
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -EEXIST)
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek log_struct_link(LOG_WARNING, link,
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek "MESSAGE=%-*s: could not set address: %s",
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek /* calling handler directly so take a ref */
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek link_get_address_handler(rtnl, m, link);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek log_debug_link(link, "addresses set");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int link_enter_set_addresses(Link *link) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek assert(link->state != _LINK_STATE_INVALID);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek link->state = LINK_STATE_SETTING_ADDRESSES;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (!link->network->static_addresses && !link->dhcp_lease &&
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek (!link->ipv4ll || ipv4ll_is_bound(link->ipv4ll) == false))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek return link_enter_set_routes(link);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_debug_link(link, "setting addresses");
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek LIST_FOREACH(addresses, ad, link->network->static_addresses) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = address_configure(ad, link, &address_handler);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek "could not set addresses: %s", strerror(-r));
eb56eb9b40950f1edcffdb7313f8de4f8572a6d5Michal Schmidt _cleanup_address_free_ Address *ll_addr = NULL;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_ipv4ll_get_address(link->ipv4ll, &addr);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_warning_link(link, "IPV4LL error: no address: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = address_new_dynamic(&ll_addr);
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate address: %s", strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen);
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering r = address_configure(ll_addr, link, &address_handler);
dad29dff1925a114e20d4eb7b47fca23c4f25fd7Lennart Poettering "could not set addresses: %s", strerror(-r));
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek _cleanup_address_free_ Address *address = NULL;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "DHCP error: no address: %s",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (!link->network->dhcp_critical) {
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_dhcp_lease_get_lifetime(link->dhcp_lease,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "DHCP error: no lifetime: %s",
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
7449bc1f34c206e3ff8e274cd74e2db950d492a1Zbigniew Jędrzejewski-Szmek log_warning_link(link, "DHCP error: no netmask: %s",
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek prefixlen = net_netmask_to_prefixlen(&netmask);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = address_new_dynamic(&address);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_error_link(link, "Could not allocate address: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek address->cinfo.ifa_prefered = lifetime;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek address->cinfo.ifa_valid = lifetime;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek /* use update rather than configure so that we will update the lifetime
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt of an existing address if it has already been configured */
c33b329709ebe2755181980a050d02ec7c81ed87Michal Schmidt r = address_update(address, link, &address_handler);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "could not set addresses: %s", strerror(-r));
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmekstatic int address_update_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
29fc0ddcd737af906986d4029579d4dfe838ba02Zbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
722b6795655149a68277b3cffeba711e1d440e5aZbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek if (r < 0 && r != -ENOENT)
a3152e7655231b94fa7b9582906fb86ab00b9c99Zbigniew Jędrzejewski-Szmek log_struct_link(LOG_WARNING, link,
d71839afd88589247d8dd42b2b09d024f521749dZbigniew Jędrzejewski-Szmek "MESSAGE=%-*s: could not update address: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek r = sd_rtnl_message_get_errno(m);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (r < 0 && r != -EADDRNOTAVAIL)
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_struct_link(LOG_WARNING, link,
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek "MESSAGE=%-*s: could not drop address: %s",
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int set_hostname_handler(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_link_unref_ Link *link = userdata;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek r = sd_bus_message_get_errno(m);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_warning_link(link, "Could not set hostname: %s", strerror(-r));
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmekstatic int link_set_hostname(Link *link, const char *hostname) {
eacbb4d33e2bb5c54311544851140efe3dd0f774Zbigniew Jędrzejewski-Szmek _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_debug_link(link, "Setting transient hostname: '%s'", hostname);
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek if (!link->manager->bus) { /* TODO: replace by assert when we can rely on kdbus */
3d090cc6f34e5970765dd1e7ee5e648a056d180dZbigniew Jędrzejewski-Szmek log_info_link(link, "Not connected to system bus, ignoring transient hostname.");
assert(m);
r = sd_rtnl_message_get_errno(m);
NULL);
unsigned prefixlen;
for (i = 0; i < routes_size; i++) {
if (r >= 0 && hostname) {
strerror(-r));
unsigned prefixlen;
strerror(-r));
strerror(-r));
strerror(-r));
if (r < 0 && r != -ENOENT) {
strerror(-r));
NULL);
NULL);
const char *hostname;
switch (event) {
case DHCP_EVENT_NO_LEASE:
case DHCP_EVENT_EXPIRED:
case DHCP_EVENT_STOP:
case DHCP_EVENT_IP_CHANGE:
case DHCP_EVENT_RENEW:
case DHCP_EVENT_IP_ACQUIRE:
if (event < 0)
strerror(-r));
NULL);
switch(event) {
case IPV4LL_EVENT_STOP:
case IPV4LL_EVENT_CONFLICT:
case IPV4LL_EVENT_BIND:
if (event < 0)
switch(event) {
case DHCP6_EVENT_STOP:
case DHCP6_EVENT_RETRANS_MAX:
case DHCP6_EVENT_IP_ACQUIRE:
if (event < 0)
event);
switch(event) {
if (event < 0)
event);
link);
/* see Documentation/networking/operstates.txt in the kernel sources */
if (unknown_flags_added)
if (carrier_gained) {
} else if (carrier_lost) {
r = sd_rtnl_message_get_errno(m);
NULL);
r = sd_rtnl_message_get_errno(m);
if (r < 0 && r != -EEXIST) {
NULL);
Iterator i;
NULL);
NULL);
NULL);
NULL);
NULL);
NULL);
if (!hostname)
return -ENOMEM;
NULL, 0);
if (r == -ENOENT) {
bool address_dropped = false;
int r, ifindex;
assert(m);
if (r < 0 || ifindex <= 0) {
if (r < 0 || !link) {
case AF_INET:
case AF_INET6:
address_dropped = true;
switch (type) {
case RTM_NEWADDR:
if (!address_dropped)
case RTM_DELADDR:
if (address_dropped) {
assert(m);
if (!device) {
return -errno;
char *ifname;
assert(m);
return -ENOMEM;
strerror(-r));
strerror(-r));
strerror(-r));
assert(f);
if (!address)
goto finish;
fprintf(f,
goto finish;
fprintf(f,
fflush(f);
r = -errno;
int config_parse_dhcp(
const char* unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
DHCPSupport s;
*dhcp = s;