X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fnetwork%2Fnetworkd-link.c;h=b597b166844b4e088c7e9855c080d879ae178c61;hb=46ba9fbae2517e6fee2a2b486ef9f06a62284b8c;hp=664cc07c724ceb39d6bf63a568d30e5273353504;hpb=ae941762628441fb3d624a57eee8d1a5c15096cf;p=elogind.git diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 664cc07c7..b597b1668 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -29,6 +29,7 @@ #include "virt.h" #include "bus-util.h" #include "network-internal.h" +#include "conf-parser.h" #include "network-util.h" #include "dhcp-lease-internal.h" @@ -124,8 +125,8 @@ static void link_free(Link *link) { free(link->lease_file); sd_ipv4ll_unref(link->ipv4ll); - sd_dhcp6_client_unref(link->dhcp6_client); + sd_icmp6_nd_unref(link->icmp6_router_discovery); hashmap_remove(link->manager->links, &link->ifindex); @@ -205,7 +206,7 @@ static int link_stop_clients(Link *link) { if (!link->network) return 0; - if (link->network->dhcp) { + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { assert(link->dhcp_client); k = sd_dhcp_client_stop(link->dhcp_client); @@ -235,12 +236,20 @@ static int link_stop_clients(Link *link) { } } - if (link->network->dhcp6) { - assert(link->dhcp6_client); + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { + assert(link->icmp6_router_discovery); + + if (link->dhcp6_client) { + k = sd_dhcp6_client_stop(link->dhcp6_client); + if (k < 0) { + log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r)); + r = k; + } + } - k = sd_dhcp6_client_stop(link->dhcp6_client); + k = sd_icmp6_nd_stop(link->icmp6_router_discovery); if (k < 0) { - log_warning_link(link, "Could not stop DHCPv6 client: %s", strerror(-r)); + log_warning_link(link, "Could not stop ICMPv6 router discovery: %s", strerror(-r)); r = k; } } @@ -299,7 +308,8 @@ static int link_enter_configured(Link *link) { assert(link->network); assert(link->state == LINK_STATE_SETTING_ROUTES); - if (link->network->dhcp_server) { + if (link->network->dhcp_server && + !sd_dhcp_server_is_running(link->dhcp_server)) { struct in_addr pool_start; Address *address; @@ -392,6 +402,51 @@ static int route_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { return 1; } +static int link_set_dhcp_routes(Link *link) { + struct sd_dhcp_route *static_routes; + size_t static_routes_size; + int r; + unsigned i; + + assert(link); + + r = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes, &static_routes_size); + if (r < 0) { + if (r != -ENOENT) + log_warning_link(link, "DHCP error: could not get routes: %s", strerror(-r)); + return r; + } + + for (i = 0; i < static_routes_size; i++) { + _cleanup_route_free_ Route *route = NULL; + + r = route_new_dynamic(&route); + if (r < 0) { + log_error_link(link, "Could not allocate route: %s", + strerror(-r)); + return r; + } + + route->family = AF_INET; + route->in_addr.in = static_routes[i].gw_addr; + route->dst_addr.in = static_routes[i].dst_addr; + route->dst_prefixlen = static_routes[i].dst_prefixlen; + route->metrics = DHCP_STATIC_ROUTE_METRIC; + + r = route_configure(route, link, &route_handler); + if (r < 0) { + log_warning_link(link, + "could not set host route: %s", strerror(-r)); + return r; + } + + link_ref(link); + link->route_messages ++; + } + + return 0; +} + static int link_enter_set_routes(Link *link) { Route *rt; int r; @@ -464,7 +519,8 @@ static int link_enter_set_routes(Link *link) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r < 0 && r != -ENOENT) { - log_warning_link(link, "DHCP error: %s", strerror(-r)); + log_warning_link(link, "DHCP error: could not get gateway: %s", + strerror(-r)); return r; } @@ -515,6 +571,9 @@ static int link_enter_set_routes(Link *link) { link_ref(link); link->route_messages ++; } + + if (link->network->dhcp_routes) + link_set_dhcp_routes(link); } if (link->route_messages == 0) { @@ -591,6 +650,7 @@ static int address_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { static int link_enter_set_addresses(Link *link) { Address *ad; int r; + uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME; assert(link); assert(link->network); @@ -667,6 +727,16 @@ static int link_enter_set_addresses(Link *link) { return r; } + if (!link->network->dhcp_critical) { + r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, + &lifetime); + if (r < 0) { + log_warning_link(link, "DHCP error: no lifetime: %s", + strerror(-r)); + return r; + } + } + r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask); if (r < 0) { log_warning_link(link, "DHCP error: no netmask: %s", @@ -685,10 +755,14 @@ static int link_enter_set_addresses(Link *link) { address->family = AF_INET; address->in_addr.in = addr; + address->cinfo.ifa_prefered = lifetime; + address->cinfo.ifa_valid = lifetime; address->prefixlen = prefixlen; address->broadcast.s_addr = addr.s_addr | ~netmask.s_addr; - r = address_configure(address, link, &address_handler); + /* use update rather than configure so that we will update the lifetime + of an existing address if it has already been configured */ + r = address_update(address, link, &address_handler); if (r < 0) { log_warning_link(link, "could not set addresses: %s", strerror(-r)); @@ -878,12 +952,11 @@ static int link_set_mtu(Link *link, uint32_t mtu) { static int dhcp_lease_lost(Link *link) { _cleanup_address_free_ Address *address = NULL; - _cleanup_route_free_ Route *route_gw = NULL; - _cleanup_route_free_ Route *route = NULL; struct in_addr addr; struct in_addr netmask; struct in_addr gateway; unsigned prefixlen; + unsigned i; int r; assert(link); @@ -891,10 +964,36 @@ static int dhcp_lease_lost(Link *link) { log_warning_link(link, "DHCP lease lost"); + if (link->network->dhcp_routes) { + struct sd_dhcp_route *routes; + size_t routes_size; + + r = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes, &routes_size); + if (r >= 0) { + for (i = 0; i < routes_size; i++) { + _cleanup_route_free_ Route *route = NULL; + + r = route_new_dynamic(&route); + if (r >= 0) { + route->family = AF_INET; + route->in_addr.in = routes[i].gw_addr; + route->dst_addr.in = routes[i].dst_addr; + route->dst_prefixlen = routes[i].dst_prefixlen; + + route_drop(route, link, &route_drop_handler); + link_ref(link); + } + } + } + } + r = address_new_dynamic(&address); if (r >= 0) { r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway); if (r >= 0) { + _cleanup_route_free_ Route *route_gw = NULL; + _cleanup_route_free_ Route *route = NULL; + r = route_new_dynamic(&route_gw); if (r >= 0) { route_gw->family = AF_INET; @@ -958,6 +1057,25 @@ static int dhcp_lease_lost(Link *link) { return 0; } +static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) { + sd_dhcp_lease *lease; + int r; + + r = sd_dhcp_client_get_lease(client, &lease); + if (r < 0) { + log_warning_link(link, "DHCP error: no lease %s", + strerror(-r)); + return r; + } + + sd_dhcp_lease_unref(link->dhcp_lease); + link->dhcp_lease = lease; + + link_enter_set_addresses(link); + + return 0; +} + static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { sd_dhcp_lease *lease; struct in_addr address; @@ -994,7 +1112,8 @@ static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) { r = sd_dhcp_lease_get_router(lease, &gateway); if (r < 0 && r != -ENOENT) { - log_warning_link(link, "DHCP error: %s", strerror(-r)); + log_warning_link(link, "DHCP error: could not get gateway: %s", + strerror(-r)); return r; } @@ -1108,6 +1227,13 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { } } + break; + case DHCP_EVENT_RENEW: + r = dhcp_lease_renew(client, link); + if (r < 0) { + link_enter_failed(link); + return; + } break; case DHCP_EVENT_IP_ACQUIRE: r = dhcp_lease_acquired(client, link); @@ -1128,7 +1254,7 @@ static void dhcp_handler(sd_dhcp_client *client, int event, void *userdata) { break; default: if (event < 0) - log_warning_link(link, "DHCP error: %s", strerror(-event)); + log_warning_link(link, "DHCP error: client failed: %s", strerror(-event)); else log_warning_link(link, "DHCP unknown event: %d", event); break; @@ -1408,7 +1534,7 @@ static int link_acquire_conf(Link *link) { } } - if (link->network->dhcp) { + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) { assert(link->dhcp_client); log_debug_link(link, "acquiring DHCPv4 lease"); @@ -1421,7 +1547,7 @@ static int link_acquire_conf(Link *link) { } } - if (link->network->dhcp6) { + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { assert(link->icmp6_router_discovery); log_debug_link(link, "discovering IPv6 routers"); @@ -1634,10 +1760,7 @@ static int link_enslaved(Link *link) { } } - if (!link->network->dhcp && !link->network->ipv4ll) - return link_enter_set_addresses(link); - - return 0; + return link_enter_set_addresses(link); } static int enslave_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) { @@ -1877,7 +2000,7 @@ static int link_configure(Link *link) { return r; } - if (link->network->dhcp) { + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V4)) { r = sd_dhcp_client_new(&link->dhcp_client); if (r < 0) return r; @@ -1903,6 +2026,14 @@ static int link_configure(Link *link) { if (r < 0) return r; } + if (link->network->dhcp_routes) { + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_STATIC_ROUTE); + if (r < 0) + return r; + r = sd_dhcp_client_set_request_option(link->dhcp_client, DHCP_OPTION_CLASSLESS_STATIC_ROUTE); + if (r < 0) + return r; + } } if (link->network->dhcp_server) { @@ -1915,7 +2046,7 @@ static int link_configure(Link *link) { return r; } - if (link->network->dhcp6) { + if (IN_SET(link->network->dhcp, DHCP_SUPPORT_BOTH, DHCP_SUPPORT_V6)) { r = sd_icmp6_nd_new(&link->icmp6_router_discovery); if (r < 0) return r; @@ -2448,3 +2579,55 @@ static const char* const link_operstate_table[_LINK_OPERSTATE_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(link_operstate, LinkOperationalState); + +static const char* const dhcp_support_table[_DHCP_SUPPORT_MAX] = { + [DHCP_SUPPORT_NONE] = "none", + [DHCP_SUPPORT_BOTH] = "both", + [DHCP_SUPPORT_V4] = "v4", + [DHCP_SUPPORT_V6] = "v6", +}; + +DEFINE_STRING_TABLE_LOOKUP(dhcp_support, DHCPSupport); + +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 *dhcp = data; + int k; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(data); + + /* Our enum shall be a superset of booleans, hence first try + * to parse as boolean, and then as enum */ + + k = parse_boolean(rvalue); + if (k > 0) + *dhcp = DHCP_SUPPORT_BOTH; + else if (k == 0) + *dhcp = DHCP_SUPPORT_NONE; + else { + DHCPSupport s; + + s = dhcp_support_from_string(rvalue); + if (s < 0){ + log_syntax(unit, LOG_ERR, filename, line, -s, "Failed to parse DHCP option, ignoring: %s", rvalue); + return 0; + } + + *dhcp = s; + } + + return 0; +}