summaryrefslogtreecommitdiffstats
path: root/src/network/networkd-dhcp4.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network/networkd-dhcp4.c')
-rw-r--r--src/network/networkd-dhcp4.c274
1 files changed, 106 insertions, 168 deletions
diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c
index 247416a750..a8d6498423 100644
--- a/src/network/networkd-dhcp4.c
+++ b/src/network/networkd-dhcp4.c
@@ -27,7 +27,7 @@
#include "sysctl-util.h"
static int dhcp4_request_address_and_routes(Link *link, bool announce);
-static int dhcp4_remove_all(Link *link);
+static int dhcp4_check_ready(Link *link);
void network_adjust_dhcp4(Network *network) {
assert(network);
@@ -54,84 +54,106 @@ void network_adjust_dhcp4(Network *network) {
network->dhcp_client_identifier = network->dhcp_anonymize ? DHCP_CLIENT_ID_MAC : DHCP_CLIENT_ID_DUID;
}
-static int dhcp4_release_old_lease(Link *link) {
+static int dhcp4_remove_address_and_routes(Link *link, bool only_marked) {
+ Address *address;
Route *route;
int k, r = 0;
assert(link);
- if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
- return 0;
-
- log_link_debug(link, "Removing old DHCPv4 address and routes.");
+ SET_FOREACH(route, link->routes) {
+ if (route->source != NETWORK_CONFIG_SOURCE_DHCP4)
+ continue;
+ if (only_marked && !route_is_marked(route))
+ continue;
- SET_FOREACH(route, link->dhcp_routes_old) {
- k = route_remove(route, NULL, link);
+ k = route_remove(route);
if (k < 0)
r = k;
+
+ route_cancel_request(route);
}
- if (link->dhcp_address_old) {
- k = address_remove(link->dhcp_address_old, link);
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
+ continue;
+ if (only_marked && !address_is_marked(address))
+ continue;
+
+ k = address_remove(address);
if (k < 0)
r = k;
+
+ address_cancel_request(address);
}
return r;
}
-static void dhcp4_check_ready(Link *link) {
+static int dhcp4_address_get(Link *link, Address **ret) {
+ Address *address;
+
+ assert(link);
+
+ SET_FOREACH(address, link->addresses) {
+ if (address->source != NETWORK_CONFIG_SOURCE_DHCP4)
+ continue;
+ if (address_is_marked(address))
+ continue;
+
+ if (ret)
+ *ret = address;
+ return 0;
+ }
+
+ return -ENOENT;
+}
+
+static int dhcp4_address_ready_callback(Address *address) {
+ assert(address);
+ assert(address->link);
+
+ /* Do not call this again. */
+ address->callback = NULL;
+
+ return dhcp4_check_ready(address->link);
+}
+
+static int dhcp4_check_ready(Link *link) {
+ Address *address;
int r;
+ assert(link);
+
if (link->dhcp4_messages > 0) {
log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
- return;
+ return 0;
}
- if (!link->dhcp_address) {
+ if (dhcp4_address_get(link, &address) < 0) {
log_link_debug(link, "%s(): DHCPv4 address is not set.", __func__);
- return;
+ return 0;
}
- if (!address_is_ready(link->dhcp_address)) {
+ if (!address_is_ready(address)) {
log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
- return;
+ address->callback = dhcp4_address_ready_callback;
+ return 0;
}
link->dhcp4_configured = true;
+ log_link_debug(link, "DHCPv4 address and routes set.");
/* New address and routes are configured now. Let's release old lease. */
- r = dhcp4_release_old_lease(link);
- if (r < 0) {
- link_enter_failed(link);
- return;
- }
+ r = dhcp4_remove_address_and_routes(link, /* only_marked = */ true);
+ if (r < 0)
+ return r;
r = sd_ipv4ll_stop(link->ipv4ll);
if (r < 0)
- log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
+ return log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address: %m");
link_check_ready(link);
-}
-
-static int dhcp4_after_route_configure(Request *req, void *object) {
- Route *route = object;
- Link *link;
- int r;
-
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ROUTE);
- assert(route);
-
- link = req->link;
-
- r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, route);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
-
- set_remove(link->dhcp_routes_old, route);
-
return 0;
}
@@ -140,7 +162,7 @@ static int dhcp4_retry(Link *link) {
assert(link);
- r = dhcp4_remove_all(link);
+ r = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
if (r < 0)
return r;
@@ -192,19 +214,29 @@ static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1;
}
- dhcp4_check_ready(link);
+ r = dhcp4_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
return 1;
}
static int dhcp4_request_route(Route *in, Link *link) {
_cleanup_(route_freep) Route *route = in;
- Request *req;
+ struct in_addr server;
+ Route *existing;
int r;
assert(route);
assert(link);
+ assert(link->dhcp_lease);
+
+ r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &server);
+ if (r < 0)
+ return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
+ route->source = NETWORK_CONFIG_SOURCE_DHCP4;
+ route->provider.in = server;
route->family = AF_INET;
if (!route->protocol_set)
route->protocol = RTPROT_DHCP;
@@ -215,20 +247,13 @@ static int dhcp4_request_route(Route *in, Link *link) {
if (route->mtu == 0)
route->mtu = link->network->dhcp_route_mtu;
- r = link_has_route(link, route);
- if (r < 0)
- return r;
- if (r == 0)
+ if (route_get(NULL, link, route, &existing) < 0) /* This is a new route. */
link->dhcp4_configured = false;
+ else
+ route_unmark(existing);
- r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
- dhcp4_route_handler, &req);
- if (r <= 0)
- return r;
-
- req->after_configure = dhcp4_after_route_configure;
-
- return 0;
+ return link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
+ dhcp4_route_handler, NULL);
}
static bool link_prefixroute(Link *link) {
@@ -675,19 +700,10 @@ static int dhcp4_request_routes_to_ntp(Link *link, const struct in_addr *gw) {
static int dhcp4_request_routes(Link *link) {
struct in_addr gw = {};
- Route *rt;
int r;
assert(link);
-
- if (!link->dhcp_lease)
- return 0;
-
- while ((rt = set_steal_first(link->dhcp_routes))) {
- r = set_ensure_put(&link->dhcp_routes_old, &route_hash_ops, rt);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
- }
+ assert(link->dhcp_lease);
r = dhcp4_request_prefix_route(link);
if (r < 0)
@@ -768,27 +784,6 @@ static int dhcp_reset_hostname(Link *link) {
return 0;
}
-static int dhcp4_remove_all(Link *link) {
- Route *route;
- int k, r = 0;
-
- assert(link);
-
- SET_FOREACH(route, link->dhcp_routes) {
- k = route_remove(route, NULL, link);
- if (k < 0)
- r = k;
- }
-
- if (link->dhcp_address) {
- k = address_remove(link->dhcp_address, link);
- if (k < 0)
- r = k;
- }
-
- return r;
-}
-
int dhcp4_lease_lost(Link *link) {
int k, r = 0;
@@ -799,12 +794,7 @@ int dhcp4_lease_lost(Link *link) {
link->dhcp4_configured = false;
- /* dhcp4_lease_lost() may be called during renewing IP address. */
- k = dhcp4_release_old_lease(link);
- if (k < 0)
- r = k;
-
- k = dhcp4_remove_all(link);
+ k = dhcp4_remove_address_and_routes(link, /* only_marked = */ false);
if (k < 0)
r = k;
@@ -819,24 +809,7 @@ int dhcp4_lease_lost(Link *link) {
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
- if (link->network->dhcp_send_decline) {
- Address *a;
-
- /* The acquired address may be still ARP probing and not configured. */
-
- SET_FOREACH(a, link->addresses_ipv4acd)
- if (!a->is_static && address_get(link, a, NULL) < 0) {
- Request req = {
- .link = link,
- .address = a,
- };
-
- log_link_debug(link, "Canceling the request to configure DHCPv4 address "IPV4_ADDRESS_FMT_STR,
- IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
- request_drop(ordered_set_get(link->manager->request_queue, &req));
- }
- }
-
+ /* If one of the above failed. Do not request nexthops and routes. */
if (r < 0)
return r;
@@ -847,43 +820,6 @@ int dhcp4_lease_lost(Link *link) {
return link_request_static_routes(link, true);
}
-static int dhcp4_address_ready_callback(Address *address) {
- assert(address);
-
- /* Do not call this again. */
- address->callback = NULL;
-
- dhcp4_check_ready(address->link);
- return 0;
-}
-
-static int dhcp4_after_address_configure(Request *req, void *object) {
- Address *address = object;
- Link *link;
- int r;
-
- assert(req);
- assert(req->link);
- assert(req->type == REQUEST_TYPE_ADDRESS);
- assert(address);
-
- link = req->link;
-
- if (!address_equal(link->dhcp_address, address)) {
- if (link->dhcp_address_old &&
- !address_equal(link->dhcp_address_old, link->dhcp_address)) {
- /* Still too old address exists? Let's remove it immediately. */
- r = address_remove(link->dhcp_address_old, link);
- if (r < 0)
- return r;
- }
- link->dhcp_address_old = link->dhcp_address;
- }
-
- link->dhcp_address = address;
- return 0;
-}
-
static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
@@ -896,12 +832,9 @@ static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
if (r <= 0)
return r;
- if (address_is_ready(link->dhcp_address)) {
- r = dhcp4_address_ready_callback(link->dhcp_address);
- if (r < 0)
- link_enter_failed(link);
- } else
- link->dhcp_address->callback = dhcp4_address_ready_callback;
+ r = dhcp4_check_ready(link);
+ if (r < 0)
+ link_enter_failed(link);
return 1;
}
@@ -911,14 +844,12 @@ static int dhcp4_request_address(Link *link, bool announce) {
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
struct in_addr address, netmask, server;
unsigned prefixlen;
- Request *req;
+ Address *existing;
int r;
assert(link);
assert(link->network);
-
- if (!link->dhcp_lease)
- return 0;
+ assert(link->dhcp_lease);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
@@ -973,6 +904,8 @@ static int dhcp4_request_address(Link *link, bool announce) {
if (r < 0)
return log_oom();
+ addr->source = NETWORK_CONFIG_SOURCE_DHCP4;
+ addr->provider.in = server;
addr->family = AF_INET;
addr->in_addr.in.s_addr = address.s_addr;
addr->cinfo.ifa_prefered = lifetime;
@@ -988,17 +921,15 @@ static int dhcp4_request_address(Link *link, bool announce) {
if (r < 0)
return r;
- if (address_get(link, addr, NULL) < 0)
+ if (address_get(link, addr, &existing) < 0) /* The address is new. */
link->dhcp4_configured = false;
+ else
+ address_unmark(existing);
r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
- dhcp4_address_handler, &req);
+ dhcp4_address_handler, NULL);
if (r < 0)
return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
- if (r == 0)
- return 0;
-
- req->after_configure = dhcp4_after_address_configure;
return 0;
}
@@ -1008,6 +939,9 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
assert(link);
+ link_mark_addresses(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
+ link_mark_routes(link, NETWORK_CONFIG_SOURCE_DHCP4, NULL);
+
r = dhcp4_request_address(link, announce);
if (r < 0)
return r;
@@ -1016,8 +950,10 @@ static int dhcp4_request_address_and_routes(Link *link, bool announce) {
if (r < 0)
return r;
- link_set_state(link, LINK_STATE_CONFIGURING);
- link_check_ready(link);
+ if (!link->dhcp4_configured) {
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ link_check_ready(link);
+ }
return 0;
}
@@ -1372,7 +1308,9 @@ static int dhcp4_set_request_address(Link *link) {
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
return 0;
- SET_FOREACH(a, link->addresses_foreign) {
+ SET_FOREACH(a, link->addresses) {
+ if (a->source != NETWORK_CONFIG_SOURCE_FOREIGN)
+ continue;
if (a->family != AF_INET)
continue;
if (link_address_is_dynamic(link, a))