network: process queued remove requests on stop (#34871)

Fixes a regression caused by 85a6f300c1
and its later commits.
Fixes #34837.
This commit is contained in:
Yu Watanabe
2024-10-31 04:03:11 +09:00
committed by GitHub
6 changed files with 96 additions and 33 deletions
+1 -9
View File
@@ -45,7 +45,7 @@ PACKAGES=(
libxkbcommon-dev
libxtables-dev
libzstd-dev
# mold
mold
mount
net-tools
python3-evdev
@@ -68,14 +68,6 @@ LINKER="${LINKER:?}"
CRYPTOLIB="${CRYPTOLIB:?}"
RELEASE="$(lsb_release -cs)"
# mold-2.2.0+ fixes some bugs breaking bootloader builds.
# TODO: Switch to distro mold with ubuntu-24.04
if [[ "$LINKER" == mold ]]; then
wget https://github.com/rui314/mold/releases/download/v2.2.0/mold-2.2.0-x86_64-linux.tar.gz
echo "d66e0230c562c2ba0e0b789cc5034e0fa2369cc843d0154920de4269cd94afeb mold-2.2.0-x86_64-linux.tar.gz" | sha256sum -c
sudo tar -xz -C /usr --strip-components=1 -f mold-2.2.0-x86_64-linux.tar.gz
fi
# Note: As we use postfixed clang/gcc binaries, we need to override $AR
# as well, otherwise meson falls back to ar from binutils which
# doesn't work with LTO
+6 -2
View File
@@ -222,7 +222,7 @@ void link_dns_settings_clear(Link *link) {
link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors);
}
static void link_free_engines(Link *link) {
void link_free_engines(Link *link) {
if (!link)
return;
@@ -379,7 +379,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
bool keep_dhcp = may_keep_dhcp &&
link->network &&
!link->network->dhcp_send_decline && /* IPv4 ACD for the DHCPv4 address is running. */
(link->manager->restarting ||
(link->manager->state == MANAGER_RESTARTING ||
FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP_ON_STOP));
if (!keep_dhcp) {
@@ -1313,9 +1313,13 @@ int link_reconfigure_impl(Link *link, bool force) {
int r;
assert(link);
assert(link->manager);
link_assign_netdev(link);
if (link->manager->state != MANAGER_RUNNING)
return 0;
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_LINGER))
return 0;
+1
View File
@@ -252,6 +252,7 @@ int link_ipv6ll_gained(Link *link);
bool link_has_ipv6_connectivity(Link *link);
int link_stop_engines(Link *link, bool may_keep_dhcp);
void link_free_engines(Link *link);
const char* link_state_to_string(LinkState s) _const_;
LinkState link_state_from_string(const char *s) _pure_;
+59 -21
View File
@@ -422,30 +422,73 @@ static int manager_connect_rtnl(Manager *m, int fd) {
static int manager_post_handler(sd_event_source *s, void *userdata) {
Manager *manager = ASSERT_PTR(userdata);
/* To release dynamic leases, we need to process queued remove requests before stopping networkd.
* This is especially important when KeepConfiguration=no. See issue #34837. */
(void) manager_process_remove_requests(manager);
(void) manager_process_requests(manager);
(void) manager_clean_all(manager);
switch (manager->state) {
case MANAGER_RUNNING:
(void) manager_process_requests(manager);
(void) manager_clean_all(manager);
return 0;
case MANAGER_TERMINATING:
case MANAGER_RESTARTING:
if (!ordered_set_isempty(manager->remove_request_queue))
return 0; /* There are some unissued remove requests. */
if (netlink_get_reply_callback_count(manager->rtnl) > 0 ||
netlink_get_reply_callback_count(manager->genl) > 0 ||
fw_ctx_get_reply_callback_count(manager->fw_ctx) > 0)
return 0; /* There are some message calls waiting for their replies. */
manager->state = MANAGER_STOPPED;
return sd_event_exit(sd_event_source_get_event(s), 0);
default:
assert_not_reached();
}
return 0;
}
static int manager_stop(Manager *manager, ManagerState state) {
assert(manager);
assert(IN_SET(state, MANAGER_TERMINATING, MANAGER_RESTARTING));
if (manager->state != MANAGER_RUNNING) {
log_debug("Already terminating or restarting systemd-networkd, refusing further operation request.");
return 0;
}
switch (state) {
case MANAGER_TERMINATING:
log_debug("Terminate operation initiated.");
break;
case MANAGER_RESTARTING:
log_debug("Restart operation initiated.");
break;
default:
assert_not_reached();
}
manager->state = state;
Link *link;
HASHMAP_FOREACH(link, manager->links_by_index) {
(void) link_stop_engines(link, /* may_keep_dhcp = */ true);
link_free_engines(link);
}
return 0;
}
static int signal_terminate_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
m->restarting = false;
log_debug("Terminate operation initiated.");
return sd_event_exit(sd_event_source_get_event(s), 0);
return manager_stop(userdata, MANAGER_TERMINATING);
}
static int signal_restart_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
Manager *m = ASSERT_PTR(userdata);
m->restarting = true;
log_debug("Restart operation initiated.");
return sd_event_exit(sd_event_source_get_event(s), 0);
return manager_stop(userdata, MANAGER_RESTARTING);
}
static int signal_reload_callback(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
@@ -614,8 +657,6 @@ int manager_new(Manager **ret, bool test_mode) {
}
Manager* manager_free(Manager *m) {
Link *link;
if (!m)
return NULL;
@@ -623,9 +664,6 @@ Manager* manager_free(Manager *m) {
free(m->state_file);
HASHMAP_FOREACH(link, m->links_by_index)
(void) link_stop_engines(link, true);
m->request_queue = ordered_set_free(m->request_queue);
m->remove_request_queue = ordered_set_free(m->remove_request_queue);
+10 -1
View File
@@ -19,6 +19,15 @@
#include "set.h"
#include "time-util.h"
typedef enum ManagerState {
MANAGER_RUNNING,
MANAGER_TERMINATING,
MANAGER_RESTARTING,
MANAGER_STOPPED,
_MANAGER_STATE_MAX,
_MANAGER_STATE_INVALID = -EINVAL,
} ManagerState;
struct Manager {
sd_netlink *rtnl;
/* lazy initialized */
@@ -35,10 +44,10 @@ struct Manager {
KeepConfiguration keep_configuration;
IPv6PrivacyExtensions ipv6_privacy_extensions;
ManagerState state;
bool test_mode;
bool enumerating;
bool dirty;
bool restarting;
bool manage_foreign_routes;
bool manage_foreign_rules;
bool manage_foreign_nexthops;
@@ -6820,6 +6820,25 @@ class NetworkdDHCPClientTests(unittest.TestCase, Utilities):
self.check_nftset('network4', r'192\.168\.5\.0/24')
self.check_nftset('ifindex', 'veth99')
# Check if DHCPv4 address and routes are removed on stop. For issue #34837.
stop_networkd(show_logs=False)
self.wait_address_dropped('veth99', f'inet {address2}/24', ipv='-4', timeout_sec=120)
print('## ip address show dev veth99 scope global')
output = check_output('ip address show dev veth99 scope global')
print(output)
self.assertNotIn(f'{address2}', output)
print('## ip route show table main dev veth99')
output = check_output('ip route show table main dev veth99')
print(output)
self.assertNotIn(f'{address2}', output)
print('## ip route show table 211 dev veth99')
output = check_output('ip route show table 211 dev veth99')
print(output)
self.assertNotIn(f'{address2}', output)
self.teardown_nftset('addr4', 'network4', 'ifindex')
def test_dhcp_client_ipv4_dbus_status(self):