Merge pull request #24348 from yuwata/network-ipv4acd-renew
network: fix IPv4ACD issues on DHCP renewal or reconfiguring interface
This commit is contained in:
@@ -143,15 +143,15 @@ Address *address_free(Address *address) {
|
||||
bool address_is_ready(const Address *a) {
|
||||
assert(a);
|
||||
|
||||
if (!ipv4acd_bound(a))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(a->flags, IFA_F_TENTATIVE))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_REMOVING))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(a->state, NETWORK_CONFIG_STATE_PROBING))
|
||||
return false;
|
||||
|
||||
if (!FLAGS_SET(a->state, NETWORK_CONFIG_STATE_CONFIGURED))
|
||||
return false;
|
||||
|
||||
@@ -1089,7 +1089,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) {
|
||||
if (!link_is_ready_to_configure(link, false))
|
||||
return false;
|
||||
|
||||
if (FLAGS_SET(address->state, NETWORK_CONFIG_STATE_PROBING))
|
||||
if (!ipv4acd_bound(address))
|
||||
return false;
|
||||
|
||||
/* Refuse adding more than the limit */
|
||||
@@ -1190,6 +1190,7 @@ int link_request_address(
|
||||
} else {
|
||||
existing->source = address->source;
|
||||
existing->provider = address->provider;
|
||||
existing->duplicate_address_detection = address->duplicate_address_detection;
|
||||
existing->lifetime_valid_usec = address->lifetime_valid_usec;
|
||||
existing->lifetime_preferred_usec = address->lifetime_preferred_usec;
|
||||
if (consume_object)
|
||||
|
||||
@@ -58,6 +58,7 @@ struct Address {
|
||||
* To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
|
||||
AddressFamily duplicate_address_detection;
|
||||
sd_ipv4acd *acd;
|
||||
bool acd_bound;
|
||||
|
||||
/* Called when address become ready */
|
||||
address_ready_callback_t callback;
|
||||
@@ -118,12 +119,6 @@ int network_drop_invalid_addresses(Network *network);
|
||||
int address_compare_func(const Address *a1, const Address *a2);
|
||||
|
||||
DEFINE_NETWORK_CONFIG_STATE_FUNCTIONS(Address, address);
|
||||
static inline void address_enter_probing(Address *address) {
|
||||
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, NETWORK_CONFIG_STATE_PROBING);
|
||||
}
|
||||
static inline void address_cancel_probing(Address *address) {
|
||||
address_update_state(address, NETWORK_CONFIG_STATE_PROBING, 0);
|
||||
}
|
||||
|
||||
void link_mark_addresses(Link *link, NetworkConfigSource source, const struct in6_addr *router);
|
||||
|
||||
|
||||
@@ -39,15 +39,41 @@ bool link_ipv4acd_supported(Link *link) {
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool address_ipv4acd_enabled(Address *address) {
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
if (address->family != AF_INET)
|
||||
return false;
|
||||
|
||||
if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
|
||||
return false;
|
||||
|
||||
/* Currently, only static and DHCP4 addresses are supported. */
|
||||
if (!IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4))
|
||||
return false;
|
||||
|
||||
if (!link_ipv4acd_supported(address->link))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ipv4acd_bound(const Address *address) {
|
||||
assert(address);
|
||||
|
||||
if (!address->acd)
|
||||
return true;
|
||||
|
||||
return address->acd_bound;
|
||||
}
|
||||
|
||||
static int static_ipv4acd_address_remove(Link *link, Address *address, bool on_conflict) {
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(address);
|
||||
|
||||
/* Prevent form the address being freed. */
|
||||
address_enter_probing(address);
|
||||
|
||||
if (!address_exists(address))
|
||||
return 0; /* Not assigned. */
|
||||
|
||||
@@ -85,9 +111,6 @@ static int dhcp4_address_on_conflict(Link *link, Address *address) {
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
|
||||
|
||||
/* make the address will be freed. */
|
||||
address_cancel_probing(address);
|
||||
|
||||
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
|
||||
return 0;
|
||||
}
|
||||
@@ -108,6 +131,8 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
|
||||
switch (event) {
|
||||
case SD_IPV4ACD_EVENT_STOP:
|
||||
address->acd_bound = false;
|
||||
|
||||
if (address->source == NETWORK_CONFIG_SOURCE_STATIC) {
|
||||
r = static_ipv4acd_address_remove(link, address, /* on_conflict = */ false);
|
||||
if (r < 0)
|
||||
@@ -119,13 +144,15 @@ static void on_acd(sd_ipv4acd *acd, int event, void *userdata) {
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_BIND:
|
||||
address->acd_bound = true;
|
||||
|
||||
log_link_debug(link, "Successfully claimed address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
address_cancel_probing(address);
|
||||
break;
|
||||
|
||||
case SD_IPV4ACD_EVENT_CONFLICT:
|
||||
address->acd_bound = false;
|
||||
|
||||
log_link_warning(link, "Dropping address "IPV4_ADDRESS_FMT_STR", as an address conflict was detected.",
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
@@ -157,6 +184,22 @@ static int ipv4acd_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void
|
||||
return link_get_by_hw_addr(m, &hw_addr, NULL) >= 0;
|
||||
}
|
||||
|
||||
static int address_ipv4acd_start(Address *address) {
|
||||
assert(address);
|
||||
assert(address->link);
|
||||
|
||||
if (!address->acd)
|
||||
return 0;
|
||||
|
||||
if (sd_ipv4acd_is_running(address->acd))
|
||||
return 0;
|
||||
|
||||
if (!link_has_carrier(address->link))
|
||||
return 0;
|
||||
|
||||
return sd_ipv4acd_start(address->acd, true);
|
||||
}
|
||||
|
||||
int ipv4acd_configure(Address *address) {
|
||||
Link *link;
|
||||
int r;
|
||||
@@ -165,23 +208,15 @@ int ipv4acd_configure(Address *address) {
|
||||
|
||||
link = ASSERT_PTR(address->link);
|
||||
|
||||
if (address->family != AF_INET)
|
||||
return 0;
|
||||
|
||||
if (!FLAGS_SET(address->duplicate_address_detection, ADDRESS_FAMILY_IPV4))
|
||||
return 0;
|
||||
|
||||
if (!link_ipv4acd_supported(link))
|
||||
return 0;
|
||||
|
||||
/* Currently, only static and DHCP4 addresses are supported. */
|
||||
assert(IN_SET(address->source, NETWORK_CONFIG_SOURCE_STATIC, NETWORK_CONFIG_SOURCE_DHCP4));
|
||||
|
||||
if (address->acd) {
|
||||
address_enter_probing(address);
|
||||
if (!address_ipv4acd_enabled(address)) {
|
||||
address->acd = sd_ipv4acd_unref(address->acd);
|
||||
address->acd_bound = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (address->acd)
|
||||
return address_ipv4acd_start(address);
|
||||
|
||||
log_link_debug(link, "Configuring IPv4ACD for address "IPV4_ADDRESS_FMT_STR,
|
||||
IPV4_ADDRESS_FMT_VAL(address->in_addr.in));
|
||||
|
||||
@@ -213,14 +248,7 @@ int ipv4acd_configure(Address *address) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link_has_carrier(link)) {
|
||||
r = sd_ipv4acd_start(address->acd, true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
address_enter_probing(address);
|
||||
return 0;
|
||||
return address_ipv4acd_start(address);
|
||||
}
|
||||
|
||||
int ipv4acd_update_mac(Link *link) {
|
||||
@@ -255,13 +283,7 @@ int ipv4acd_start(Link *link) {
|
||||
assert(link);
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (!address->acd)
|
||||
continue;
|
||||
|
||||
if (sd_ipv4acd_is_running(address->acd))
|
||||
continue;
|
||||
|
||||
r = sd_ipv4acd_start(address->acd, true);
|
||||
r = address_ipv4acd_start(address);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ typedef struct Address Address;
|
||||
typedef struct Link Link;
|
||||
|
||||
bool link_ipv4acd_supported(Link *link);
|
||||
bool ipv4acd_bound(const Address *address);
|
||||
int ipv4acd_configure(Address *address);
|
||||
int ipv4acd_update_mac(Link *link);
|
||||
int ipv4acd_start(Link *link);
|
||||
|
||||
@@ -26,7 +26,6 @@ DEFINE_STRING_TABLE_LOOKUP_TO_STRING(network_config_source, NetworkConfigSource)
|
||||
|
||||
int network_config_state_to_string_alloc(NetworkConfigState s, char **ret) {
|
||||
static const char* states[] = {
|
||||
[LOG2U(NETWORK_CONFIG_STATE_PROBING)] = "probing",
|
||||
[LOG2U(NETWORK_CONFIG_STATE_REQUESTING)] = "requesting",
|
||||
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURING)] = "configuring",
|
||||
[LOG2U(NETWORK_CONFIG_STATE_CONFIGURED)] = "configured",
|
||||
|
||||
@@ -27,14 +27,13 @@ typedef enum NetworkConfigSource {
|
||||
} NetworkConfigSource;
|
||||
|
||||
typedef enum NetworkConfigState {
|
||||
NETWORK_CONFIG_STATE_PROBING = 1 << 0, /* address is probing by IPv4ACD */
|
||||
NETWORK_CONFIG_STATE_REQUESTING = 1 << 1, /* request is queued */
|
||||
NETWORK_CONFIG_STATE_CONFIGURING = 1 << 2, /* e.g. address_configure() is called, but no response is received yet */
|
||||
NETWORK_CONFIG_STATE_CONFIGURED = 1 << 3, /* e.g. address_configure() is called and received a response from kernel.
|
||||
NETWORK_CONFIG_STATE_REQUESTING = 1 << 0, /* request is queued */
|
||||
NETWORK_CONFIG_STATE_CONFIGURING = 1 << 1, /* e.g. address_configure() is called, but no response is received yet */
|
||||
NETWORK_CONFIG_STATE_CONFIGURED = 1 << 2, /* e.g. address_configure() is called and received a response from kernel.
|
||||
* Note that address may not be ready yet, so please use address_is_ready()
|
||||
* to check whether the address can be usable or not. */
|
||||
NETWORK_CONFIG_STATE_MARKED = 1 << 4, /* used GC'ing the old config */
|
||||
NETWORK_CONFIG_STATE_REMOVING = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
|
||||
NETWORK_CONFIG_STATE_MARKED = 1 << 3, /* used GC'ing the old config */
|
||||
NETWORK_CONFIG_STATE_REMOVING = 1 << 4, /* e.g. address_remove() is called, but no response is received yet */
|
||||
} NetworkConfigState;
|
||||
|
||||
static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
[Match]
|
||||
Name=veth99
|
||||
|
||||
[Network]
|
||||
DHCP=ipv4
|
||||
IPv6AcceptRA=false
|
||||
|
||||
[DHCPv4]
|
||||
SendDecline=yes
|
||||
@@ -10,6 +10,7 @@ DHCPPrefixDelegation=yes
|
||||
|
||||
[DHCPv4]
|
||||
Use6RD=yes
|
||||
SendDecline=yes
|
||||
|
||||
[DHCPPrefixDelegation]
|
||||
UplinkInterface=:self
|
||||
|
||||
@@ -5289,7 +5289,7 @@ class NetworkdDHCPPDTests(unittest.TestCase, Utilities):
|
||||
|
||||
self.verify_dhcp4_6rd(tunnel_name)
|
||||
|
||||
print('Wait for the DHCP lease to be expired')
|
||||
print('Wait for the DHCP lease to be renewed/rebind')
|
||||
time.sleep(120)
|
||||
|
||||
self.wait_online(['veth99:routable', 'test1:routable', 'dummy97:routable', 'dummy98:routable', 'dummy99:degraded',
|
||||
|
||||
Reference in New Issue
Block a user