Then, replace address_remove_and_drop() with it.
If an address is requested, and the request is already called,
we may not received its reply and notification from the kernel, and
the corresponding address object may not be remmbered. Even in such
case, we need to remove the address, otherwise the address will come
later after the function called.
int address_remove(Address *address, Link *link) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
- Request *req;
int r;
assert(address);
link_ref(link);
address_enter_removing(address);
- if (address_get_request(link, address, &req) >= 0)
- address_enter_removing(req->userdata);
/* The operational state is determined by address state and carrier state. Hence, if we remove
* an address, the operational state may be changed. */
return 0;
}
-int address_remove_and_drop(Address *address) {
- if (!address || !address->link)
- return 0;
+int address_remove_and_cancel(Address *address, Link *link) {
+ bool waiting = false;
+ Request *req;
- address_cancel_request(address);
+ assert(address);
+ assert(link);
+ assert(link->manager);
- if (address_exists(address))
- return address_remove(address, address->link);
+ /* If the address is remembered by the link, then use the remembered object. */
+ (void) address_get(link, address, &address);
- return address_drop(address);
+ /* Cancel the request for the address. If the request is already called but we have not received the
+ * notification about the request, then explicitly remove the address. */
+ if (address_get_request(link, address, &req) >= 0) {
+ waiting = req->waiting_reply;
+ request_detach(link->manager, req);
+ address_cancel_requesting(address);
+ }
+
+ /* If we know the address will come or already exists, remove it. */
+ if (waiting || (address->link && address_exists(address)))
+ return address_remove(address, link);
+
+ return 0;
}
bool link_address_is_dynamic(const Link *link, const Address *address) {
return 0;
}
-void address_cancel_request(Address *address) {
- Request req;
-
- assert(address);
- assert(address->link);
-
- if (!address_is_requesting(address))
- return;
-
- req = (Request) {
- .link = address->link,
- .type = REQUEST_TYPE_ADDRESS,
- .userdata = address,
- .hash_func = (hash_func_t) address_hash_func,
- .compare_func = (compare_func_t) address_compare_func,
- };
-
- request_detach(address->link->manager, &req);
- address_cancel_requesting(address);
-}
-
int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
_cleanup_(address_freep) Address *tmp = NULL;
struct ifa_cacheinfo cinfo;
int address_get_harder(Link *link, const Address *in, Address **ret);
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
int address_remove(Address *address, Link *link);
-int address_remove_and_drop(Address *address);
+int address_remove_and_cancel(Address *address, Link *link);
int address_dup(const Address *src, Address **ret);
bool address_is_ready(const Address *a);
bool link_check_addresses_ready(Link *link, NetworkConfigSource source);
int manager_get_address(Manager *manager, int family, const union in_addr_union *address, unsigned char prefixlen, Address **ret);
bool manager_has_address(Manager *manager, int family, const union in_addr_union *address);
-void address_cancel_request(Address *address);
int link_request_address(
Link *link,
const Address *address,
link_remove_dhcp_pd_subnet_prefix(link, &prefix);
- RET_GATHER(ret, address_remove_and_drop(address));
+ RET_GATHER(ret, address_remove_and_cancel(address, link));
}
}
if (only_marked && !address_is_marked(address))
continue;
- RET_GATHER(ret, address_remove_and_drop(address));
+ RET_GATHER(ret, address_remove_and_cancel(address, link));
}
return ret;
if (only_marked && !address_is_marked(address))
continue;
- RET_GATHER(ret, address_remove_and_drop(address));
+ RET_GATHER(ret, address_remove_and_cancel(address, link));
}
return ret;
else
log_link_debug(link, "Removing address %s, as the ACD client is stopped.", IN4_ADDR_TO_STRING(&address->in_addr.in));
+ /* Do not call address_remove_and_cancel() here. Otherwise, the request is cancelled, and the
+ * interface may be in configured state without the address. */
r = address_remove(address, link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to remove address %s: %m", IN4_ADDR_TO_STRING(&address->in_addr.in));
static int ipv4ll_address_lost(Link *link) {
_cleanup_(address_freep) Address *address = NULL;
- Address *existing;
int r;
assert(link);
if (r < 0)
return r;
- if (address_get(link, address, &existing) < 0)
- return 0;
-
- if (existing->source != NETWORK_CONFIG_SOURCE_IPV4LL)
- return 0;
-
- if (!address_exists(existing))
- return 0;
-
log_link_debug(link, "IPv4 link-local release "IPV4_ADDRESS_FMT_STR,
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
- return address_remove(existing, link);
+ return address_remove_and_cancel(address, link);
}
static int ipv4ll_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Request *req, Link *link, Address *address) {
if (address->lifetime_valid_usec >= timestamp_usec)
continue; /* the address is still valid */
- r = address_remove_and_drop(address);
+ r = address_remove_and_cancel(address, link);
if (r < 0)
RET_GATHER(ret, log_link_warning_errno(link, r, "Failed to remove outdated SLAAC address, ignoring: %m"));
}