#include <linux/if.h>
#include <linux/if_arp.h>
-#include "escape.h"
#include "alloc-util.h"
#include "dhcp-client-internal.h"
#include "hostname-setup.h"
#include "network-internal.h"
#include "networkd-address.h"
#include "networkd-dhcp4.h"
+#include "networkd-ipv4acd.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
+#include "networkd-nexthop.h"
+#include "networkd-queue.h"
+#include "networkd-route.h"
+#include "networkd-setlink.h"
#include "networkd-state-file.h"
#include "string-table.h"
#include "strv.h"
#include "sysctl-util.h"
-#include "web-util.h"
-static int dhcp4_update_address(Link *link, bool announce);
+static int dhcp4_request_address_and_routes(Link *link, bool announce);
static int dhcp4_remove_all(Link *link);
void network_adjust_dhcp4(Network *network) {
log_link_debug(link, "Removing old DHCPv4 address and routes.");
SET_FOREACH(route, link->dhcp_routes_old) {
- k = route_remove(route, NULL, link, NULL);
+ k = route_remove(route, NULL, link);
if (k < 0)
r = k;
}
if (link->dhcp_address_old) {
- k = address_remove(link->dhcp_address_old, link, NULL);
+ k = address_remove(link->dhcp_address_old, link);
if (k < 0)
r = k;
}
static void dhcp4_check_ready(Link *link) {
int r;
- if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
+ if (link->dhcp4_messages > 0) {
+ log_link_debug(link, "%s(): DHCPv4 address and routes are not set.", __func__);
return;
+ }
+
+ if (!link->dhcp_address) {
+ log_link_debug(link, "%s(): DHCPv4 address is not set.", __func__);
+ return;
+ }
- if (link->dhcp4_messages > 0)
+ if (!address_is_ready(link->dhcp_address)) {
+ log_link_debug(link, "%s(): DHCPv4 address is not ready.", __func__);
return;
+ }
link->dhcp4_configured = true;
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;
+}
+
static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r;
r = dhcp4_remove_all(link);
if (r < 0)
link_enter_failed(link);
+
+ r = link_request_static_nexthops(link, true);
+ if (r < 0)
+ link_enter_failed(link);
+
+ r = link_request_static_routes(link, true);
+ if (r < 0)
+ link_enter_failed(link);
+
+ r = dhcp4_request_address_and_routes(link, false);
+ if (r < 0)
+ link_enter_failed(link);
+
return 1;
}
return 1;
}
-static int dhcp_route_configure(Route *route, Link *link) {
- Route *ret;
+static int dhcp4_request_route(Route *in, Link *link) {
+ _cleanup_(route_freep) Route *route = in;
+ Request *req;
int r;
assert(route);
assert(link);
- r = route_configure(route, link, dhcp4_route_handler, &ret);
+ r = link_has_route(link, route);
if (r < 0)
- return log_link_error_errno(link, r, "Failed to set DHCPv4 route: %m");
-
- link->dhcp4_messages++;
+ return r;
+ if (r == 0)
+ link->dhcp4_configured = false;
- r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, ret);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
+ r = link_request_route(link, TAKE_PTR(route), true, &link->dhcp4_messages,
+ dhcp4_route_handler, &req);
+ if (r <= 0)
+ return r;
- (void) set_remove(link->dhcp_routes_old, ret);
+ req->after_configure = dhcp4_after_route_configure;
return 0;
}
link->manager->dhcp4_prefix_root_cannot_set_table;
}
-static int link_set_dhcp_prefix_route(Link *link) {
+static int dhcp4_request_prefix_route(Link *link) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr address, netmask;
int r;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
- return dhcp_route_configure(route, link);
+ return dhcp4_request_route(TAKE_PTR(route), link);
}
-static int link_set_dhcp_route_to_gateway(Link *link, const struct in_addr *gw) {
+static int dhcp4_request_route_to_gateway(Link *link, const struct in_addr *gw) {
_cleanup_(route_freep) Route *route = NULL;
struct in_addr address;
int r;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
- return dhcp_route_configure(route, link);
+ return dhcp4_request_route(TAKE_PTR(route), link);
}
-static int dhcp_route_configure_auto(
- Route *route,
+static int dhcp4_request_route_auto(
+ Route *in,
Link *link,
const struct in_addr *gw) {
+ _cleanup_(route_freep) Route *route = in;
struct in_addr address, netmask, prefix;
uint8_t prefixlen;
int r;
assert(link->dhcp_lease);
assert(gw);
- /* The route object may be reused in an iteration. All elements must be set or cleared. */
-
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return r;
return 0;
}
- r = link_set_dhcp_route_to_gateway(link, gw);
+ r = dhcp4_request_route_to_gateway(link, gw);
if (r < 0)
return r;
route->prefsrc.in = address;
}
- return dhcp_route_configure(route, link);
+ return dhcp4_request_route(TAKE_PTR(route), link);
}
-static int link_set_dhcp_static_routes(Link *link) {
+static int dhcp4_request_static_routes(Link *link, struct in_addr *ret_default_gw) {
_cleanup_free_ sd_dhcp_route **static_routes = NULL;
bool classless_route = false, static_route = false;
- _cleanup_(route_freep) Route *route = NULL;
+ struct in_addr default_gw = {};
int n, r;
assert(link);
assert(link->dhcp_lease);
-
- if (!link->network->dhcp_use_routes)
- return 0;
+ assert(ret_default_gw);
n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
if (IN_SET(n, 0, -ENODATA)) {
/* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
* the DHCP client MUST ignore the Static Routes option. */
if (classless_route && static_route)
- log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option");
+ log_link_debug(link, "Classless static routes received from DHCP server: ignoring static-route option");
- r = route_new(&route);
- if (r < 0)
- return r;
+ if (!link->network->dhcp_use_routes) {
+ if (!classless_route)
+ return 0;
- route->family = AF_INET;
- route->gw_family = AF_INET;
- route->protocol = RTPROT_DHCP;
- route->priority = link->network->dhcp_route_metric;
- route->table = link_get_dhcp_route_table(link);
- route->mtu = link->network->dhcp_route_mtu;
+ /* Even if UseRoutes=no, try to find default gateway to make semi-static routes and
+ * routes to DNS or NTP servers can be configured in later steps. */
+ for (int i = 0; i < n; i++) {
+ struct in_addr dst;
+ uint8_t prefixlen;
+
+ if (sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
+ continue;
+
+ r = sd_dhcp_route_get_destination(static_routes[i], &dst);
+ if (r < 0)
+ return r;
+
+ if (in4_addr_is_set(&dst))
+ continue;
+
+ r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &prefixlen);
+ if (r < 0)
+ return r;
+
+ if (prefixlen != 0)
+ continue;
+
+ r = sd_dhcp_route_get_gateway(static_routes[i], ret_default_gw);
+ if (r < 0)
+ return r;
+
+ break;
+ }
+
+ /* Do not return 1 here, to ensure the router option can override the default gateway
+ * that was found. */
+ return 0;
+ }
for (int i = 0; i < n; i++) {
+ _cleanup_(route_freep) Route *route = NULL;
struct in_addr gw;
if (sd_dhcp_route_get_option(static_routes[i]) !=
(classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE))
continue;
+ r = route_new(&route);
+ if (r < 0)
+ return r;
+
+ route->family = AF_INET;
+ route->gw_family = AF_INET;
+ route->protocol = RTPROT_DHCP;
+ route->priority = link->network->dhcp_route_metric;
+ route->table = link_get_dhcp_route_table(link);
+ route->mtu = link->network->dhcp_route_mtu;
+
r = sd_dhcp_route_get_gateway(static_routes[i], &gw);
if (r < 0)
return r;
if (r < 0)
return r;
- r = dhcp_route_configure_auto(route, link, &gw);
+ /* When classless static routes are provided, then router option will be ignored. To
+ * use the default gateway later in other routes, e.g., routes to dns servers, here we
+ * need to find the default gateway in the classless static routes. */
+ if (classless_route &&
+ in4_addr_is_null(&route->dst.in) && route->dst_prefixlen == 0 &&
+ in4_addr_is_null(&default_gw))
+ default_gw = gw;
+
+ r = dhcp4_request_route_auto(TAKE_PTR(route), link, &gw);
if (r < 0)
return r;
}
+ *ret_default_gw = default_gw;
return classless_route;
}
-static int link_set_dhcp_gateway(Link *link) {
+static int dhcp4_request_gateway(Link *link, struct in_addr *gw) {
_cleanup_(route_freep) Route *route = NULL;
const struct in_addr *router;
struct in_addr address;
- Route *rt;
int r;
assert(link);
assert(link->dhcp_lease);
-
- if (!link->network->dhcp_use_gateway)
- return 0;
+ assert(gw);
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return 0;
}
+ if (!link->network->dhcp_use_gateway) {
+ /* When no classless static route is provided, even if UseGateway=no, use the gateway
+ * address to configure semi-static routes or routes to DNS or NTP servers. Note, if
+ * neither UseRoutes= nor UseGateway= is disabled, use the default gateway in classless
+ * static routes if provided (in that case, in4_addr_is_null(gw) below is true). */
+ if (in4_addr_is_null(gw))
+ *gw = router[0];
+ return 0;
+ }
+
/* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host
* so that we can route no matter the netmask or existing kernel route tables. */
- r = link_set_dhcp_route_to_gateway(link, &router[0]);
+ r = dhcp4_request_route_to_gateway(link, &router[0]);
if (r < 0)
return r;
route->table = link_get_dhcp_route_table(link);
route->mtu = link->network->dhcp_route_mtu;
- r = dhcp_route_configure(route, link);
+ r = dhcp4_request_route(TAKE_PTR(route), link);
if (r < 0)
return r;
+ /* When no classless static route is provided, or UseRoutes=no, then use the router address to
+ * configure semi-static routes and routes to DNS or NTP servers in later steps. */
+ *gw = router[0];
+ return 0;
+}
+
+static int dhcp4_request_semi_static_routes(Link *link, const struct in_addr *gw) {
+ Route *rt;
+ int r;
+
+ assert(link);
+ assert(link->dhcp_lease);
+ assert(link->network);
+ assert(gw);
+
+ if (in4_addr_is_null(gw))
+ return 0;
+
HASHMAP_FOREACH(rt, link->network->routes_by_section) {
+ _cleanup_(route_freep) Route *route = NULL;
+
if (!rt->gateway_from_dhcp_or_ra)
continue;
if (rt->gw_family != AF_INET)
continue;
- rt->gw.in = router[0];
- if (!rt->protocol_set)
- rt->protocol = RTPROT_DHCP;
- if (!rt->priority_set)
- rt->priority = link->network->dhcp_route_metric;
- if (!rt->table_set)
- rt->table = link_get_dhcp_route_table(link);
- if (rt->mtu == 0)
- rt->mtu = link->network->dhcp_route_mtu;
-
- r = dhcp_route_configure(rt, link);
+ r = dhcp4_request_route_to_gateway(link, gw);
+ if (r < 0)
+ return r;
+
+ r = route_dup(rt, &route);
+ if (r < 0)
+ return r;
+
+ route->gw.in = *gw;
+ if (!route->protocol_set)
+ route->protocol = RTPROT_DHCP;
+ if (!route->priority_set)
+ route->priority = link->network->dhcp_route_metric;
+ if (!route->table_set)
+ route->table = link_get_dhcp_route_table(link);
+ if (route->mtu == 0)
+ route->mtu = link->network->dhcp_route_mtu;
+
+ r = dhcp4_request_route(TAKE_PTR(route), link);
if (r < 0)
return r;
}
return 0;
}
-static int link_set_dns_routes(Link *link) {
- _cleanup_(route_freep) Route *route = NULL;
+static int dhcp4_request_routes_to_servers(
+ Link *link,
+ const struct in_addr *servers,
+ size_t n_servers,
+ const struct in_addr *gw) {
+
+ int r;
+
+ assert(link);
+ assert(link->dhcp_lease);
+ assert(link->network);
+ assert(servers || n_servers == 0);
+ assert(gw);
+
+ for (size_t i = 0; i < n_servers; i++) {
+ _cleanup_(route_freep) Route *route = NULL;
+
+ if (in4_addr_is_null(&servers[i]))
+ continue;
+
+ r = route_new(&route);
+ if (r < 0)
+ return r;
+
+ route->family = AF_INET;
+ route->dst.in = servers[i];
+ route->dst_prefixlen = 32;
+ route->protocol = RTPROT_DHCP;
+ route->priority = link->network->dhcp_route_metric;
+ route->table = link_get_dhcp_route_table(link);
+ route->mtu = link->network->dhcp_route_mtu;
+
+ r = dhcp4_request_route_auto(TAKE_PTR(route), link, gw);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+static int dhcp4_request_routes_to_dns(Link *link, const struct in_addr *gw) {
const struct in_addr *dns;
- struct in_addr address;
- int n, r;
+ int r;
assert(link);
assert(link->dhcp_lease);
assert(link->network);
+ assert(gw);
if (!link->network->dhcp_use_dns ||
!link->network->dhcp_routes_to_dns)
return 0;
- n = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
- if (IN_SET(n, 0, -ENODATA))
+ r = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
+ if (IN_SET(r, 0, -ENODATA))
return 0;
- if (n < 0)
- return n;
-
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return r;
- r = route_new(&route);
- if (r < 0)
- return r;
+ return dhcp4_request_routes_to_servers(link, dns, r, gw);
+}
- route->family = AF_INET;
- route->dst_prefixlen = 32;
- route->prefsrc.in = address;
- route->scope = RT_SCOPE_LINK;
- route->protocol = RTPROT_DHCP;
- route->priority = link->network->dhcp_route_metric;
- route->table = link_get_dhcp_route_table(link);
- route->mtu = link->network->dhcp_route_mtu;
+static int dhcp4_request_routes_to_ntp(Link *link, const struct in_addr *gw) {
+ const struct in_addr *ntp;
+ int r;
- for (int i = 0; i < n; i ++) {
- route->dst.in = dns[i];
+ assert(link);
+ assert(link->dhcp_lease);
+ assert(link->network);
+ assert(gw);
- r = dhcp_route_configure(route, link);
- if (r < 0)
- return r;
- }
+ if (!link->network->dhcp_use_ntp ||
+ !link->network->dhcp_routes_to_ntp)
+ return 0;
- return 0;
+ r = sd_dhcp_lease_get_ntp(link->dhcp_lease, &ntp);
+ if (IN_SET(r, 0, -ENODATA))
+ return 0;
+ if (r < 0)
+ return r;
+
+ return dhcp4_request_routes_to_servers(link, ntp, r, gw);
}
-static int link_set_dhcp_routes(Link *link) {
+static int dhcp4_request_routes(Link *link) {
+ struct in_addr gw = {};
Route *rt;
int r;
assert(link);
- if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
- return 0;
-
- if (!link->network) /* link went down while we configured the IP addresses? */
- return 0;
-
- if (!link_has_carrier(link) && !link->network->configure_without_carrier)
- /* During configuring addresses, the link lost its carrier. As networkd is dropping
- * the addresses now, let's not configure the routes either. */
+ if (!link->dhcp_lease)
return 0;
while ((rt = set_steal_first(link->dhcp_routes))) {
return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
}
- r = link_set_dhcp_prefix_route(link);
+ r = dhcp4_request_prefix_route(link);
if (r < 0)
- return log_link_error_errno(link, r, "DHCP error: Could not set prefix route: %m");
+ return log_link_error_errno(link, r, "DHCP error: Could not request prefix route: %m");
- r = link_set_dhcp_static_routes(link);
+ r = dhcp4_request_static_routes(link, &gw);
if (r < 0)
- return log_link_error_errno(link, r, "DHCP error: Could not set static routes: %m");
+ return log_link_error_errno(link, r, "DHCP error: Could not request static routes: %m");
if (r == 0) {
/* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
* a Router option, the DHCP client MUST ignore the Router option. */
- r = link_set_dhcp_gateway(link);
+ r = dhcp4_request_gateway(link, &gw);
if (r < 0)
- return log_link_error_errno(link, r, "DHCP error: Could not set gateway: %m");
+ return log_link_error_errno(link, r, "DHCP error: Could not request gateway: %m");
}
- r = link_set_dns_routes(link);
+ r = dhcp4_request_semi_static_routes(link, &gw);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: Could not request routes with Gateway=_dhcp4 setting: %m");
+
+ r = dhcp4_request_routes_to_dns(link, &gw);
+ if (r < 0)
+ return log_link_error_errno(link, r, "DHCP error: Could not request routes to DNS servers: %m");
+
+ r = dhcp4_request_routes_to_ntp(link, &gw);
if (r < 0)
- return log_link_error_errno(link, r, "DHCP error: Could not set routes to DNS servers: %m");
+ return log_link_error_errno(link, r, "DHCP error: Could not request routes to NTP servers: %m");
return 0;
}
if (link->original_mtu == mtu)
return 0;
- r = link_set_mtu(link, link->original_mtu);
+ r = link_request_to_set_mtu(link, link->original_mtu);
if (r < 0)
return log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
return 0;
}
-static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(m);
- assert(link);
- assert(link->dhcp4_remove_messages > 0);
-
- link->dhcp4_remove_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -ESRCH)
- log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 route, ignoring");
-
- if (link->dhcp4_remove_messages == 0) {
- r = dhcp4_update_address(link, false);
- if (r < 0)
- link_enter_failed(link);
- }
-
- return 1;
-}
-
-static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
- int r;
-
- assert(m);
- assert(link);
- assert(link->dhcp4_remove_messages > 0);
-
- link->dhcp4_remove_messages--;
-
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
-
- r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EADDRNOTAVAIL)
- log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
- else
- (void) manager_rtnl_process_address(rtnl, m, link->manager);
-
- if (link->dhcp4_remove_messages == 0) {
- r = dhcp4_update_address(link, false);
- if (r < 0)
- link_enter_failed(link);
- }
-
- return 1;
-}
-
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, dhcp4_remove_route_handler);
+ k = route_remove(route, NULL, link);
if (k < 0)
r = k;
- else
- link->dhcp4_remove_messages++;
}
if (link->dhcp_address) {
- k = address_remove(link->dhcp_address, link, dhcp4_remove_address_handler);
+ k = address_remove(link->dhcp_address, link);
if (k < 0)
r = k;
- else
- link->dhcp4_remove_messages++;
}
return r;
}
-static int dhcp_lease_lost(Link *link) {
+int dhcp4_lease_lost(Link *link) {
int k, r = 0;
assert(link);
link->dhcp4_configured = false;
- /* dhcp_lease_lost() may be called during renewing IP address. */
+ /* dhcp4_lease_lost() may be called during renewing IP address. */
k = dhcp4_release_old_lease(link);
if (k < 0)
r = k;
link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
link_dirty(link);
- (void) sd_ipv4acd_stop(link->dhcp_acd);
+ if (link->network->dhcp_send_decline) {
+ Address *a;
- return r;
-}
+ /* The acquired address may be still ARP probing and not configured. */
-static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
- _cleanup_free_ char *pretty = NULL;
- union in_addr_union address = {};
- Link *link;
- int r;
+ SET_FOREACH(a, link->addresses_ipv4acd)
+ if (!a->is_static && address_get(link, a, NULL) < 0) {
+ Request req = {
+ .link = link,
+ .address = a,
+ };
- assert(acd);
- assert(userdata);
-
- link = userdata;
-
- switch (event) {
- case SD_IPV4ACD_EVENT_STOP:
- log_link_debug(link, "Stopping ACD client for DHCP4...");
- return;
-
- case SD_IPV4ACD_EVENT_BIND:
- if (DEBUG_LOGGING) {
- (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
- (void) in_addr_to_string(AF_INET, &address, &pretty);
- log_link_debug(link, "Successfully claimed DHCP4 address %s", strna(pretty));
- }
- link->dhcp4_address_bind = true;
- dhcp4_check_ready(link);
- break;
-
- case SD_IPV4ACD_EVENT_CONFLICT:
- (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
- (void) in_addr_to_string(AF_INET, &address, &pretty);
- log_link_warning(link, "DAD conflict. Dropping DHCP4 address %s", strna(pretty));
-
- r = sd_dhcp_client_send_decline(link->dhcp_client);
- if (r < 0)
- log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
-
- if (link->dhcp_lease) {
- r = dhcp_lease_lost(link);
- if (r < 0)
- link_enter_failed(link);
- }
- break;
-
- default:
- assert_not_reached("Invalid IPv4ACD event.");
- }
-
- (void) sd_ipv4acd_stop(acd);
-
- return;
-}
-
-static int dhcp4_configure_dad(Link *link) {
- int r;
-
- assert(link);
- assert(link->manager);
- assert(link->network);
-
- if (!link->network->dhcp_send_decline)
- return 0;
-
- if (!link->dhcp_acd) {
- r = sd_ipv4acd_new(&link->dhcp_acd);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
- if (r < 0)
- return r;
+ 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));
+ }
}
- r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
if (r < 0)
return r;
- r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether);
+ r = link_request_static_nexthops(link, true);
if (r < 0)
return r;
- return 0;
+ return link_request_static_routes(link, true);
}
-static int dhcp4_dad_update_mac(Link *link) {
- bool running;
- int r;
-
- assert(link);
-
- if (!link->dhcp_acd)
- return 0;
-
- running = sd_ipv4acd_is_running(link->dhcp_acd);
-
- r = sd_ipv4acd_stop(link->dhcp_acd);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether);
- if (r < 0)
- return r;
+static int dhcp4_address_ready_callback(Address *address) {
+ assert(address);
- if (running) {
- r = sd_ipv4acd_start(link->dhcp_acd, true);
- if (r < 0)
- return r;
- }
+ /* Do not call this again. */
+ address->callback = NULL;
+ dhcp4_check_ready(address->link);
return 0;
}
-static int dhcp4_start_acd(Link *link) {
- union in_addr_union addr;
- struct in_addr old;
- int r;
-
- if (!link->network->dhcp_send_decline)
- return 0;
-
- if (!link->dhcp_lease)
- return 0;
-
- (void) sd_ipv4acd_stop(link->dhcp_acd);
-
- link->dhcp4_address_bind = false;
-
- r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr.in);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_address(link->dhcp_acd, &addr.in);
- if (r < 0)
- return r;
-
- r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
- if (r < 0)
- return r;
-
- if (DEBUG_LOGGING) {
- _cleanup_free_ char *pretty = NULL;
-
- (void) in_addr_to_string(AF_INET, &addr, &pretty);
- log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
- }
-
- r = sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr.in, &old));
- if (r < 0)
- return r;
-
- return 1;
-}
-
-static int dhcp4_address_ready_callback(Address *address) {
+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 = address->link;
+ link = req->link;
- /* Do not call this again. */
- address->callback = NULL;
-
- r = link_set_dhcp_routes(link);
- if (r < 0)
- return r;
-
- /* Reconfigure static routes as kernel may remove some routes when lease expires. */
- r = link_set_routes(link);
- if (r < 0)
- return r;
-
- r = dhcp4_start_acd(link);
- if (r < 0)
- return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCP4 address: %m");
+ 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;
+ }
- dhcp4_check_ready(link);
+ link->dhcp_address = address;
return 0;
}
int r;
assert(link);
+ assert(link->dhcp4_messages > 0);
- if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
- return 1;
+ link->dhcp4_messages--;
- r = sd_netlink_message_get_errno(m);
- if (r < 0 && r != -EEXIST) {
- log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 address");
- link_enter_failed(link);
- return 1;
- } else if (r >= 0)
- (void) manager_rtnl_process_address(rtnl, m, link->manager);
+ r = address_configure_handler_internal(rtnl, m, link, "Could not set DHCPv4 address");
+ if (r <= 0)
+ return r;
if (address_is_ready(link->dhcp_address)) {
r = dhcp4_address_ready_callback(link->dhcp_address);
- if (r < 0) {
+ if (r < 0)
link_enter_failed(link);
- return 1;
- }
} else
link->dhcp_address->callback = dhcp4_address_ready_callback;
return 1;
}
-static int dhcp4_update_address(Link *link, bool announce) {
+static int dhcp4_request_address(Link *link, bool announce) {
_cleanup_(address_freep) Address *addr = NULL;
uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
struct in_addr address, netmask;
unsigned prefixlen;
- Address *ret;
+ Request *req;
int r;
assert(link);
if (!link->dhcp_lease)
return 0;
- link_set_state(link, LINK_STATE_CONFIGURING);
- link->dhcp4_configured = false;
-
- /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are called, the
- * related flags must be cleared. Otherwise, the link becomes configured state before routes
- * are configured. */
- link->static_routes_configured = false;
- link->static_nexthops_configured = false;
-
r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no address: %m");
addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
addr->route_metric = link->network->dhcp_route_metric;
+ addr->duplicate_address_detection = link->network->dhcp_send_decline ? ADDRESS_FAMILY_IPV4 : ADDRESS_FAMILY_NO;
+
+ if (link->network->dhcp_label) {
+ addr->label = strdup(link->network->dhcp_label);
+ if (!addr->label)
+ return log_oom();
+ }
+
+ if (address_get(link, addr, NULL) < 0)
+ link->dhcp4_configured = false;
- /* allow reusing an existing address and simply update its lifetime
- * in case it already exists */
- r = address_configure(addr, link, dhcp4_address_handler, &ret);
+ r = link_request_address(link, TAKE_PTR(addr), true, &link->dhcp4_messages,
+ dhcp4_address_handler, &req);
if (r < 0)
- return log_link_error_errno(link, r, "Failed to set DHCPv4 address: %m");
+ return log_link_error_errno(link, r, "Failed to request DHCPv4 address: %m");
+ if (r == 0)
+ return 0;
- if (!address_equal(link->dhcp_address, ret))
- link->dhcp_address_old = link->dhcp_address;
- link->dhcp_address = ret;
+ req->after_configure = dhcp4_after_address_configure;
+
+ return 0;
+}
+
+static int dhcp4_request_address_and_routes(Link *link, bool announce) {
+ int r;
+
+ assert(link);
+
+ r = dhcp4_request_address(link, announce);
+ if (r < 0)
+ return r;
+
+ r = dhcp4_request_routes(link);
+ if (r < 0)
+ return r;
+
+ link_set_state(link, LINK_STATE_CONFIGURING);
+ link_check_ready(link);
return 0;
}
link->dhcp_lease = sd_dhcp_lease_ref(lease);
link_dirty(link);
- return dhcp4_update_address(link, false);
+ return dhcp4_request_address_and_routes(link, false);
}
static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
r = sd_dhcp_lease_get_mtu(lease, &mtu);
if (r >= 0) {
- r = link_set_mtu(link, mtu);
+ r = link_request_to_set_mtu(link, mtu);
if (r < 0)
log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
}
}
}
- if (link->dhcp4_remove_messages == 0) {
- r = dhcp4_update_address(link, true);
- if (r < 0)
- return r;
- } else
- log_link_debug(link,
- "The link has previously assigned DHCPv4 address or routes. "
- "The newly assigned address and routes will set up after old ones are removed.");
-
- return 0;
+ return dhcp4_request_address_and_routes(link, true);
}
static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
r = dhcp_lease_acquired(client, link);
if (r < 0)
- (void) dhcp_lease_lost(link);
+ (void) dhcp4_lease_lost(link);
return r;
}
if (link->network->dhcp_send_release) {
r = sd_dhcp_client_send_release(client);
if (r < 0)
- log_link_warning_errno(link, r, "Failed to send DHCP RELEASE, ignoring: %m");
+ log_link_full_errno(link,
+ ERRNO_IS_DISCONNECT(r) ? LOG_DEBUG : LOG_WARNING,
+ r, "Failed to send DHCP RELEASE, ignoring: %m");
}
- r = dhcp_lease_lost(link);
+ r = dhcp4_lease_lost(link);
if (r < 0) {
link_enter_failed(link);
return r;
}
if (link->dhcp_lease) {
- r = dhcp_lease_lost(link);
+ r = dhcp4_lease_lost(link);
if (r < 0) {
link_enter_failed(link);
return r;
else {
r = gethostname_strict(&hostname);
if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to get hostname: %m");
hn = hostname;
}
r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
if (r == -EINVAL && hostname)
/* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
- log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
+ log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
else if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set hostname: %m");
return 0;
}
duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IAID+DUID: %m");
break;
}
case DHCP_CLIENT_ID_DUID_ONLY: {
duid->raw_data_len > 0 ? duid->raw_data : NULL,
duid->raw_data_len);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set DUID: %m");
break;
}
case DHCP_CLIENT_ID_MAC: {
- const uint8_t *hw_addr = link->hw_addr.addr.bytes;
+ const uint8_t *hw_addr = link->hw_addr.bytes;
size_t hw_addr_len = link->hw_addr.length;
if (link->iftype == ARPHRD_INFINIBAND && hw_addr_len == INFINIBAND_ALEN) {
hw_addr,
hw_addr_len);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set client ID: %m");
break;
}
default:
- assert_not_reached("Unknown client identifier type.");
+ assert_not_reached();
}
return 0;
}
-static int dhcp4_configure_duid(Link *link) {
- assert(link);
-
- if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
- return 1;
-
- return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
-}
-
static int dhcp4_set_request_address(Link *link) {
Address *a;
if (!a)
return 0;
- log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
+ log_link_debug(link, "DHCPv4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
}
if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
r = parse_boolean(val);
if (r < 0)
- log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
+ log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
else
- log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
+ log_link_debug(link, "DHCPv4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
}
return r == true;
}
-int dhcp4_configure(Link *link) {
+static int dhcp4_configure(Link *link) {
sd_dhcp_option *send_option;
void *request_options;
int r;
assert(link);
assert(link->network);
- if (!link_dhcp4_enabled(link))
- return 0;
-
if (link->dhcp_client)
- return -EBUSY; /* Already configured. */
-
- r = dhcp4_configure_duid(link);
- if (r <= 0)
- return r;
+ return log_link_debug_errno(link, SYNTHETIC_ERRNO(EBUSY), "DHCPv4 client is already configured.");
r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to allocate DHCPv4 client: %m");
r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to attach event to DHCPv4 client: %m");
r = sd_dhcp_client_set_mac(link->dhcp_client,
- link->hw_addr.addr.bytes,
- link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
+ link->hw_addr.bytes,
+ link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
link->hw_addr.length, link->iftype);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MAC address: %m");
r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set ifindex: %m");
r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set callback: %m");
r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for broadcast: %m");
if (link->mtu > 0) {
r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MTU: %m");
}
if (!link->network->dhcp_anonymize) {
if (link->network->dhcp_use_mtu) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for MTU: %m");
}
if (link->network->dhcp_use_routes) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for static route: %m");
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for classless static route: %m");
}
if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for domain search list: %m");
}
if (link->network->dhcp_use_ntp) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for NTP server: %m");
}
if (link->network->dhcp_use_sip) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for SIP server: %m");
}
if (link->network->dhcp_use_timezone) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for timezone: %m");
}
SET_FOREACH(request_options, link->network->dhcp_request_options) {
r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set request flag for '%u': %m", option);
}
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
if (r == -EEXIST)
continue;
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
}
ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
if (r == -EEXIST)
continue;
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set send option: %m");
}
r = dhcp4_set_hostname(link);
r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
link->network->dhcp_vendor_class_identifier);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set vendor class identifier: %m");
}
if (link->network->dhcp_mudurl) {
r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set MUD URL: %m");
}
if (link->network->dhcp_user_class) {
r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set user class: %m");
}
}
if (link->network->dhcp_client_port > 0) {
r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set listen port: %m");
}
if (link->network->dhcp_max_attempts > 0) {
r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set max attempts: %m");
}
if (link->network->dhcp_ip_service_type > 0) {
r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set IP service type: %m");
}
if (link->network->dhcp_fallback_lease_lifetime > 0) {
r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed set to lease lifetime: %m");
}
r = dhcp4_set_request_address(link);
if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
-
- r = dhcp4_configure_dad(link);
- if (r < 0)
- return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
+ return log_link_debug_errno(link, r, "DHCPv4 CLIENT: Failed to set initial DHCPv4 address: %m");
return dhcp4_set_client_identifier(link);
}
if (!link->dhcp_client)
return 0;
- r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes,
- link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
+ r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.bytes,
+ link->bcast_addr.length > 0 ? link->bcast_addr.bytes : NULL,
link->hw_addr.length, link->iftype);
if (r < 0)
return r;
- r = dhcp4_set_client_identifier(link);
+ return dhcp4_set_client_identifier(link);
+}
+
+int dhcp4_start(Link *link) {
+ int r;
+
+ assert(link);
+
+ if (!link->dhcp_client)
+ return 0;
+
+ if (!link_has_carrier(link))
+ return 0;
+
+ if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
+ return 0;
+
+ r = sd_dhcp_client_start(link->dhcp_client);
if (r < 0)
return r;
- r = dhcp4_dad_update_mac(link);
- if (r < 0)
+ return 1;
+}
+
+static int dhcp4_configure_duid(Link *link) {
+ assert(link);
+
+ if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
+ return 1;
+
+ return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
+}
+
+int request_process_dhcp4_client(Request *req) {
+ Link *link;
+ int r;
+
+ assert(req);
+ assert(req->link);
+ assert(req->type == REQUEST_TYPE_DHCP4_CLIENT);
+
+ link = req->link;
+
+ if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
+ return 0;
+
+ r = dhcp4_configure_duid(link);
+ if (r <= 0)
return r;
- return 0;
+ r = dhcp4_configure(req->link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to configure DHCPv4 client: %m");
+
+ r = dhcp4_start(link);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m");
+
+ log_link_debug(link, "DHCPv4 client is configured%s.",
+ r > 0 ? ", acquiring DHCPv4 lease" : "");
+
+ return 1;
}
-int dhcp4_start(Link *link) {
+int link_request_dhcp4_client(Link *link) {
+ int r;
+
assert(link);
- if (!link->dhcp_client)
+ if (!link_dhcp4_enabled(link))
return 0;
- if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
+ if (link->dhcp_client)
return 0;
- log_link_debug(link, "Acquiring DHCPv4 lease");
+ r = link_queue_request(link, REQUEST_TYPE_DHCP4_CLIENT, NULL, false, NULL, NULL, NULL);
+ if (r < 0)
+ return log_link_warning_errno(link, r, "Failed to request configuring of the DHCPv4 client: %m");
- return sd_dhcp_client_start(link->dhcp_client);
+ log_link_debug(link, "Requested configuring of the DHCPv4 client.");
+ return 0;
}
int config_parse_dhcp_max_attempts(
return 0;
}
-int config_parse_dhcp_mud_url(
+int config_parse_dhcp_fallback_lease_lifetime(
const char *unit,
const char *filename,
unsigned line,
void *data,
void *userdata) {
- _cleanup_free_ char *unescaped = NULL;
- Network *network = data;
- int r;
+ Network *network = userdata;
+ uint32_t k;
assert(filename);
+ assert(section);
assert(lvalue);
assert(rvalue);
+ assert(data);
if (isempty(rvalue)) {
- network->dhcp_mudurl = mfree(network->dhcp_mudurl);
- return 0;
- }
-
- r = cunescape(rvalue, 0, &unescaped);
- if (r < 0) {
- log_syntax(unit, LOG_WARNING, filename, line, r,
- "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
+ network->dhcp_fallback_lease_lifetime = 0;
return 0;
}
- if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
+ /* We accept only "forever" or "infinity". */
+ if (STR_IN_SET(rvalue, "forever", "infinity"))
+ k = CACHE_INFO_INFINITY_LIFE_TIME;
+ else {
log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
-
+ "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
return 0;
}
- return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
+ network->dhcp_fallback_lease_lifetime = k;
+
+ return 0;
}
-int config_parse_dhcp_fallback_lease_lifetime(const char *unit,
+int config_parse_dhcp_label(
+ const char *unit,
const char *filename,
unsigned line,
const char *section,
const char *rvalue,
void *data,
void *userdata) {
- Network *network = userdata;
- uint32_t k;
+
+ char **label = data;
assert(filename);
- assert(section);
assert(lvalue);
assert(rvalue);
assert(data);
if (isempty(rvalue)) {
- network->dhcp_fallback_lease_lifetime = 0;
+ *label = mfree(*label);
return 0;
}
- /* We accept only "forever" or "infinity". */
- if (STR_IN_SET(rvalue, "forever", "infinity"))
- k = CACHE_INFO_INFINITY_LIFE_TIME;
- else {
+ if (!address_label_valid(rvalue)) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
- "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
+ "Address label is too long or invalid, ignoring assignment: %s", rvalue);
return 0;
}
- network->dhcp_fallback_lease_lifetime = k;
-
- return 0;
+ return free_and_strdup_warn(label, rvalue);
}
static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {