From: Tom Gundersen Date: Wed, 6 Aug 2014 13:54:03 +0000 (+0200) Subject: networkd: link - split out ipv4ll handling X-Git-Tag: v216~166 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=b22d8a00f48f3c5fc4510b4acd3e1a43e731e592 networkd: link - split out ipv4ll handling --- diff --git a/Makefile.am b/Makefile.am index 6fbfc5924..e65406faa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4942,6 +4942,7 @@ libsystemd_networkd_core_la_SOURCES = \ src/libsystemd-network/network-internal.h \ src/network/networkd.h \ src/network/networkd-link.h \ + src/network/networkd-ipv4ll.h \ src/network/networkd-netdev.h \ src/network/networkd-netdev-tunnel.h \ src/network/networkd-netdev-veth.h \ @@ -4963,6 +4964,7 @@ libsystemd_networkd_core_la_SOURCES = \ src/network/networkd-netdev-bond.c \ src/network/networkd-netdev-bridge.c \ src/network/networkd-link.c \ + src/network/networkd-ipv4ll.c \ src/network/networkd-network.c \ src/network/networkd-address.c \ src/network/networkd-route.c \ diff --git a/src/network/networkd-ipv4ll.c b/src/network/networkd-ipv4ll.c new file mode 100644 index 000000000..5467bc372 --- /dev/null +++ b/src/network/networkd-ipv4ll.c @@ -0,0 +1,248 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2013-2014 Tom Gundersen + + systemd is free software; you can redistribute it and/or modify it + under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + systemd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with systemd; If not, see . +***/ + +#include +#include + +#include "networkd-link.h" +#include "network-internal.h" + +static int ipv4ll_address_lost(Link *link) { + _cleanup_address_free_ Address *address = NULL; + _cleanup_route_free_ Route *route = NULL; + struct in_addr addr; + int r; + + assert(link); + + link->ipv4ll_route = false; + link->ipv4ll_address = false; + + r = sd_ipv4ll_get_address(link->ipv4ll, &addr); + if (r < 0) + return 0; + + log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u", + ADDRESS_FMT_VAL(addr)); + + r = address_new_dynamic(&address); + if (r < 0) { + log_error_link(link, "Could not allocate address: %s", strerror(-r)); + return r; + } + + address->family = AF_INET; + address->in_addr.in = addr; + address->prefixlen = 16; + address->scope = RT_SCOPE_LINK; + + address_drop(address, link, &link_address_drop_handler); + + r = route_new_dynamic(&route, RTPROT_UNSPEC); + if (r < 0) { + log_error_link(link, "Could not allocate route: %s", + strerror(-r)); + return r; + } + + route->family = AF_INET; + route->scope = RT_SCOPE_LINK; + route->metrics = IPV4LL_ROUTE_METRIC; + + route_drop(route, link, &link_route_drop_handler); + + link_client_handler(link); + + return 0; +} + +static int ipv4ll_route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + _cleanup_link_unref_ Link *link = userdata; + int r; + + assert(link); + assert(!link->ipv4ll_route); + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_error_link(link, "could not set ipv4ll route: %s", strerror(-r)); + link_enter_failed(link); + } + + link->ipv4ll_route = true; + + if (link->ipv4ll_address == true) + link_client_handler(link); + + return 1; +} + +static int ipv4ll_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { + _cleanup_link_unref_ Link *link = userdata; + int r; + + assert(link); + assert(!link->ipv4ll_address); + + r = sd_rtnl_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_error_link(link, "could not set ipv4ll address: %s", strerror(-r)); + link_enter_failed(link); + } else if (r >= 0) { + /* calling handler directly so take a ref */ + link_ref(link); + link_get_address_handler(rtnl, m, link); + } + + link->ipv4ll_address = true; + + if (link->ipv4ll_route == true) + link_client_handler(link); + + return 1; +} + +static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { + _cleanup_address_free_ Address *ll_addr = NULL; + _cleanup_route_free_ Route *route = NULL; + struct in_addr address; + int r; + + assert(ll); + assert(link); + + r = sd_ipv4ll_get_address(ll, &address); + if (r == -ENOENT) + return 0; + else if (r < 0) + return r; + + log_debug_link(link, "IPv4 link-local claim %u.%u.%u.%u", + ADDRESS_FMT_VAL(address)); + + r = address_new_dynamic(&ll_addr); + if (r < 0) + return r; + + ll_addr->family = AF_INET; + ll_addr->in_addr.in = address; + ll_addr->prefixlen = 16; + ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); + ll_addr->scope = RT_SCOPE_LINK; + + r = address_configure(ll_addr, link, ipv4ll_address_handler); + if (r < 0) + return r; + + link->ipv4ll_address = false; + + r = route_new_dynamic(&route, RTPROT_STATIC); + if (r < 0) + return r; + + route->family = AF_INET; + route->scope = RT_SCOPE_LINK; + route->metrics = IPV4LL_ROUTE_METRIC; + + r = route_configure(route, link, ipv4ll_route_handler); + if (r < 0) + return r; + + link->ipv4ll_route = false; + + return 0; +} + +static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ + Link *link = userdata; + int r; + + assert(link); + assert(link->network); + assert(link->manager); + + if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) + return; + + switch(event) { + case IPV4LL_EVENT_STOP: + case IPV4LL_EVENT_CONFLICT: + r = ipv4ll_address_lost(link); + if (r < 0) { + link_enter_failed(link); + return; + } + break; + case IPV4LL_EVENT_BIND: + r = ipv4ll_address_claimed(ll, link); + if (r < 0) { + link_enter_failed(link); + return; + } + break; + default: + if (event < 0) + log_warning_link(link, "IPv4 link-local error: %s", strerror(-event)); + else + log_warning_link(link, "IPv4 link-local unknown event: %d", event); + break; + } +} + +int ipv4ll_configure(Link *link) { + uint8_t seed[8]; + int r; + + assert(link); + assert(link->network); + assert(link->network->ipv4ll); + + r = sd_ipv4ll_new(&link->ipv4ll); + if (r < 0) + return r; + + if (link->udev_device) { + r = net_get_unique_predictable_data(link->udev_device, seed); + if (r >= 0) { + r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); + if (r < 0) + return r; + } + } + + r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0); + if (r < 0) + return r; + + r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); + if (r < 0) + return r; + + r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex); + if (r < 0) + return r; + + r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link); + if (r < 0) + return r; + + return 0; +} diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index f73b06916..3bef1a57a 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -245,7 +245,7 @@ static int link_stop_clients(Link *link) { return r; } -static void link_enter_failed(Link *link) { +void link_enter_failed(Link *link) { assert(link); if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) @@ -260,6 +260,17 @@ static void link_enter_failed(Link *link) { link_save(link); } +void link_client_handler(Link *link) { + assert(link); + + if (link->ipv4ll_address && link->ipv4ll_route) + log_debug_link(link, "IPv4LL configured"); + else + log_debug_link(link, "IPv4LL not configured"); + + return; +} + static Address* link_find_dhcp_server_address(Link *link) { Address *address; @@ -428,20 +439,6 @@ static int link_set_dhcp_routes(Link *link) { return 0; } -static bool ipv4ll_is_bound(sd_ipv4ll *ll) { - int r; - struct in_addr addr; - - if (!ll) - return false; - - r = sd_ipv4ll_get_address(ll, &addr); - if (r < 0) - return false; - - return true; -} - static int link_enter_set_routes(Link *link) { Route *rt; int r; @@ -464,31 +461,6 @@ static int link_enter_set_routes(Link *link) { link->route_messages ++; } - if (ipv4ll_is_bound(link->ipv4ll)) { - _cleanup_route_free_ Route *route = NULL; - - r = route_new_dynamic(&route, RTPROT_STATIC); - if (r < 0) { - log_error_link(link, "Could not allocate route: %s", - strerror(-r)); - return r; - } - - route->family = AF_INET; - route->scope = RT_SCOPE_LINK; - route->metrics = IPV4LL_ROUTE_METRIC; - - r = route_configure(route, link, &route_handler); - if (r < 0) { - log_warning_link(link, - "could not set routes: %s", strerror(-r)); - link_enter_failed(link); - return r; - } - - link->route_messages ++; - } - if (link->dhcp_lease) { _cleanup_route_free_ Route *route = NULL; _cleanup_route_free_ Route *route_gw = NULL; @@ -561,7 +533,7 @@ static int link_enter_set_routes(Link *link) { return 0; } -static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { +int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -584,7 +556,7 @@ static int route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) return 1; } -static int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { +int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -670,42 +642,6 @@ static int link_enter_set_addresses(Link *link) { link->addr_messages ++; } - if (link->ipv4ll) { - _cleanup_address_free_ Address *ll_addr = NULL; - struct in_addr addr; - - r = sd_ipv4ll_get_address(link->ipv4ll, &addr); - if (r < 0 && r != -ENOENT) { - log_warning_link(link, "IPV4LL error: no address: %s", - strerror(-r)); - return r; - } - - if (r != -ENOENT) { - r = address_new_dynamic(&ll_addr); - if (r < 0) { - log_error_link(link, "Could not allocate address: %s", strerror(-r)); - return r; - } - - ll_addr->family = AF_INET; - ll_addr->in_addr.in = addr; - ll_addr->prefixlen = 16; - ll_addr->broadcast.s_addr = ll_addr->in_addr.in.s_addr | htonl(0xfffffffflu >> ll_addr->prefixlen); - ll_addr->scope = RT_SCOPE_LINK; - - r = address_configure(ll_addr, link, &address_handler); - if (r < 0) { - log_warning_link(link, - "could not set addresses: %s", strerror(-r)); - link_enter_failed(link); - return r; - } - - link->addr_messages ++; - } - } - if (link->dhcp_lease) { _cleanup_address_free_ Address *address = NULL; struct in_addr addr; @@ -773,7 +709,7 @@ static int link_enter_set_addresses(Link *link) { return 0; } -static int address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { +int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { _cleanup_link_unref_ Link *link = userdata; int r; @@ -940,7 +876,7 @@ static int dhcp_lease_lost(Link *link) { route->dst_addr.in = routes[i].dst_addr; route->dst_prefixlen = routes[i].dst_prefixlen; - route_drop(route, link, &route_drop_handler); + route_drop(route, link, &link_route_drop_handler); } } } @@ -960,7 +896,7 @@ static int dhcp_lease_lost(Link *link) { route_gw->dst_prefixlen = 32; route_gw->scope = RT_SCOPE_LINK; - route_drop(route_gw, link, &route_drop_handler); + route_drop(route_gw, link, &link_route_drop_handler); } r = route_new_dynamic(&route, RTPROT_UNSPEC); @@ -968,7 +904,7 @@ static int dhcp_lease_lost(Link *link) { route->family = AF_INET; route->in_addr.in = gateway; - route_drop(route, link, &route_drop_handler); + route_drop(route, link, &link_route_drop_handler); } } @@ -980,7 +916,7 @@ static int dhcp_lease_lost(Link *link) { address->in_addr.in = addr; address->prefixlen = prefixlen; - address_drop(address, link, &address_drop_handler); + address_drop(address, link, &link_address_drop_handler); } if (link->network->dhcp_mtu) { @@ -1195,109 +1131,6 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { return; } -static int ipv4ll_address_lost(Link *link) { - int r; - struct in_addr addr; - - assert(link); - - r = sd_ipv4ll_get_address(link->ipv4ll, &addr); - if (r >= 0) { - _cleanup_address_free_ Address *address = NULL; - _cleanup_route_free_ Route *route = NULL; - - log_debug_link(link, "IPv4 link-local release %u.%u.%u.%u", - ADDRESS_FMT_VAL(addr)); - - r = address_new_dynamic(&address); - if (r < 0) { - log_error_link(link, "Could not allocate address: %s", strerror(-r)); - return r; - } - - address->family = AF_INET; - address->in_addr.in = addr; - address->prefixlen = 16; - address->scope = RT_SCOPE_LINK; - - address_drop(address, link, &address_drop_handler); - - r = route_new_dynamic(&route, RTPROT_UNSPEC); - if (r < 0) { - log_error_link(link, "Could not allocate route: %s", - strerror(-r)); - return r; - } - - route->family = AF_INET; - route->scope = RT_SCOPE_LINK; - route->metrics = 99; - - route_drop(route, link, &route_drop_handler); - } - - return 0; -} - -static int ipv4ll_address_claimed(sd_ipv4ll *ll, Link *link) { - struct in_addr address; - int r; - - assert(ll); - assert(link); - - r = sd_ipv4ll_get_address(ll, &address); - if (r < 0) - return r; - - log_struct_link(LOG_INFO, link, - "MESSAGE=%-*s: IPv4 link-local address %u.%u.%u.%u", - IFNAMSIZ, - link->ifname, - ADDRESS_FMT_VAL(address), - NULL); - - link_enter_set_addresses(link); - - return 0; -} - -static void ipv4ll_handler(sd_ipv4ll *ll, int event, void *userdata){ - Link *link = userdata; - int r; - - assert(link); - assert(link->network); - assert(link->manager); - - if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) - return; - - switch(event) { - case IPV4LL_EVENT_STOP: - case IPV4LL_EVENT_CONFLICT: - r = ipv4ll_address_lost(link); - if (r < 0) { - link_enter_failed(link); - return; - } - break; - case IPV4LL_EVENT_BIND: - r = ipv4ll_address_claimed(ll, link); - if (r < 0) { - link_enter_failed(link); - return; - } - break; - default: - if (event < 0) - log_warning_link(link, "IPv4 link-local error: %s", strerror(-event)); - else - log_warning_link(link, "IPv4 link-local unknown event: %d", event); - break; - } -} - static void dhcp6_handler(sd_dhcp6_client *client, int event, void *userdata) { Link *link = userdata; @@ -1766,37 +1599,11 @@ static int link_configure(Link *link) { int r; assert(link); + assert(link->network); assert(link->state == LINK_STATE_INITIALIZING); if (link->network->ipv4ll) { - uint8_t seed[8]; - - r = sd_ipv4ll_new(&link->ipv4ll); - if (r < 0) - return r; - - if (link->udev_device) { - r = net_get_unique_predictable_data(link->udev_device, seed); - if (r >= 0) { - r = sd_ipv4ll_set_address_seed(link->ipv4ll, seed); - if (r < 0) - return r; - } - } - - r = sd_ipv4ll_attach_event(link->ipv4ll, NULL, 0); - if (r < 0) - return r; - - r = sd_ipv4ll_set_mac(link->ipv4ll, &link->mac); - if (r < 0) - return r; - - r = sd_ipv4ll_set_index(link->ipv4ll, link->ifindex); - if (r < 0) - return r; - - r = sd_ipv4ll_set_callback(link->ipv4ll, ipv4ll_handler, link); + r = ipv4ll_configure(link); if (r < 0) return r; } diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 9f54c8c39..1d0b4665e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -76,7 +76,10 @@ struct Link { sd_dhcp_lease *dhcp_lease; char *lease_file; uint16_t original_mtu; + sd_ipv4ll *ipv4ll; + bool ipv4ll_address; + bool ipv4ll_route; LIST_HEAD(Address, pool_addresses); @@ -92,15 +95,24 @@ int link_get(Manager *m, int ifindex, Link **ret); int link_add(Manager *manager, sd_rtnl_message *message, Link **ret); void link_drop(Link *link); -int link_update(Link *link, sd_rtnl_message *message); -int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata); +int link_get_address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); +int link_address_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); +int link_route_drop_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata); +void link_enter_failed(Link *link); int link_initialized(Link *link, struct udev_device *device); +void link_client_handler(Link *link); + +int link_update(Link *link, sd_rtnl_message *message); +int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata); + int link_save(Link *link); bool link_has_carrier(unsigned flags, uint8_t operstate); +int ipv4ll_configure(Link *link); + const char* link_state_to_string(LinkState s) _const_; LinkState link_state_from_string(const char *s) _pure_;