Merge pull request #34054 from yuwata/network-failed-state

network: several fixlets for reconfiguration after entered failed state
This commit is contained in:
Yu Watanabe
2024-08-22 01:22:29 +09:00
committed by GitHub
5 changed files with 87 additions and 83 deletions
+32 -32
View File
@@ -683,15 +683,21 @@ static int client_initialize(sd_dhcp_client *client) {
static void client_stop(sd_dhcp_client *client, int error) {
assert(client);
DHCP_CLIENT_DONT_DESTROY(client);
if (error < 0)
log_dhcp_client_errno(client, error, "STOPPED: %m");
else if (error == SD_DHCP_CLIENT_EVENT_STOP)
log_dhcp_client(client, "STOPPED");
else
log_dhcp_client(client, "STOPPED: Unknown event");
if (sd_dhcp_client_is_running(client)) {
if (error < 0)
log_dhcp_client_errno(client, error, "STOPPED: %m");
else if (error == SD_DHCP_CLIENT_EVENT_STOP)
log_dhcp_client(client, "STOPPED");
else
log_dhcp_client(client, "STOPPED: Unknown event");
client_notify(client, error);
client_notify(client, error);
} else if (error < 0) {
log_dhcp_client_errno(client, error, "FAILED: %m");
client_notify(client, error);
}
client_initialize(client);
}
@@ -2132,14 +2138,8 @@ static int client_receive_message_raw(
}
int sd_dhcp_client_send_renew(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->fd >= 0, -EINVAL);
if (client->state != DHCP_STATE_BOUND)
return 0;
assert(client->lease);
if (!sd_dhcp_client_is_running(client) || client->state != DHCP_STATE_BOUND)
return 0; /* do nothing */
client->start_delay = 0;
client->discover_attempt = 1;
@@ -2193,14 +2193,13 @@ int sd_dhcp_client_start(sd_dhcp_client *client) {
}
int sd_dhcp_client_send_release(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->lease, -EUNATCH);
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
if (!sd_dhcp_client_is_running(client) || !client->lease)
return 0; /* do nothing */
r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset);
if (r < 0)
return r;
@@ -2224,18 +2223,21 @@ int sd_dhcp_client_send_release(sd_dhcp_client *client) {
log_dhcp_client(client, "RELEASE");
return 0;
/* This function is mostly called when stopping daemon. Hence, do not call client_stop() or
* client_restart(). Otherwise, the notification callback will be called again and we may easily
* enter an infinite loop. */
client_initialize(client);
return 1; /* sent and stopped. */
}
int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
assert_return(client, -EINVAL);
assert_return(sd_dhcp_client_is_running(client), -ESTALE);
assert_return(client->lease, -EUNATCH);
_cleanup_free_ DHCPPacket *release = NULL;
size_t optoffset, optlen;
int r;
if (!sd_dhcp_client_is_running(client) || !client->lease)
return 0; /* do nothing */
r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset);
if (r < 0)
return r;
@@ -2258,15 +2260,13 @@ int sd_dhcp_client_send_decline(sd_dhcp_client *client) {
log_dhcp_client(client, "DECLINE");
client_stop(client, SD_DHCP_CLIENT_EVENT_STOP);
/* This function is mostly called when the acquired address conflicts with another host.
* Restarting the daemon to acquire another address. */
r = client_restart(client);
if (r < 0)
return r;
if (client->state != DHCP_STATE_STOPPED) {
r = sd_dhcp_client_start(client);
if (r < 0)
return r;
}
return 0;
return 1; /* sent and restarted. */
}
int sd_dhcp_client_stop(sd_dhcp_client *client) {
+3 -3
View File
@@ -111,20 +111,20 @@ static int dhcp4_address_on_conflict(Link *link) {
assert(link);
assert(link->dhcp_client);
log_link_warning(link, "Dropping DHCPv4 lease, as an address conflict was detected.");
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)
/* Unlikely, but during probing the address, the lease may be lost. */
return 0;
log_link_warning(link, "Dropping DHCPv4 lease, as an address conflict was detected.");
r = dhcp4_lease_lost(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to drop DHCPv4 lease: %m");
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes it. */
/* It is not necessary to call address_remove() here, as dhcp4_lease_lost() removes the address. */
return 0;
}
+2 -6
View File
@@ -666,14 +666,10 @@ int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_
return 1; /* Polkit will call us back */
r = link_reconfigure(l, /* force = */ true);
if (r > 0)
r = link_save_and_clean_full(l, /* also_save_manager = */ true);
if (r < 0)
return r;
if (r > 0) {
link_set_state(l, LINK_STATE_INITIALIZED);
r = link_save_and_clean_full(l, /* also_save_manager = */ true);
if (r < 0)
return r;
}
return sd_bus_reply_method_return(message, NULL);
}
+46 -29
View File
@@ -427,8 +427,6 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
}
void link_enter_failed(Link *link) {
int r;
assert(link);
if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
@@ -444,13 +442,8 @@ void link_enter_failed(Link *link) {
}
log_link_info(link, "Trying to reconfigure the interface.");
r = link_reconfigure(link, /* force = */ true);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
goto stop;
}
return;
if (link_reconfigure(link, /* force = */ true) > 0)
return;
stop:
(void) link_stop_engines(link, /* may_keep_dhcp = */ false);
@@ -1451,8 +1444,14 @@ int link_reconfigure(Link *link, bool force) {
return 0; /* 0 means no-op. */
r = link_call_getlink(link, force ? link_force_reconfigure_handler : link_reconfigure_handler);
if (r < 0)
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
link_enter_failed(link);
return r;
}
if (force || link->state == LINK_STATE_FAILED)
link_set_state(link, LINK_STATE_INITIALIZED);
return 1; /* 1 means the interface will be reconfigured. */
}
@@ -1463,17 +1462,26 @@ typedef struct ReconfigureData {
sd_bus_message *message;
} ReconfigureData;
static ReconfigureData* reconfigure_data_free(ReconfigureData *data) {
if (!data)
return NULL;
link_unref(data->link);
sd_bus_message_unref(data->message);
return mfree(data);
}
DEFINE_TRIVIAL_CLEANUP_FUNC(ReconfigureData*, reconfigure_data_free);
static void reconfigure_data_destroy_callback(ReconfigureData *data) {
int r;
assert(data);
assert(data->link);
assert(data->manager);
assert(data->manager->reloading > 0);
assert(data->message);
link_unref(data->link);
data->manager->reloading--;
if (data->manager->reloading <= 0) {
r = sd_bus_reply_method_return(data->message, NULL);
@@ -1481,8 +1489,7 @@ static void reconfigure_data_destroy_callback(ReconfigureData *data) {
log_warning_errno(r, "Failed to send reply for 'Reload' DBus method, ignoring: %m");
}
sd_bus_message_unref(data->message);
free(data);
reconfigure_data_free(data);
}
static int reconfigure_handler_on_bus_method_reload(sd_netlink *rtnl, sd_netlink_message *m, ReconfigureData *data) {
@@ -1493,7 +1500,7 @@ static int reconfigure_handler_on_bus_method_reload(sd_netlink *rtnl, sd_netlink
int link_reconfigure_on_bus_method_reload(Link *link, sd_bus_message *message) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
_cleanup_free_ ReconfigureData *data = NULL;
_cleanup_(reconfigure_data_freep) ReconfigureData *data = NULL;
int r;
assert(link);
@@ -1505,19 +1512,11 @@ int link_reconfigure_on_bus_method_reload(Link *link, sd_bus_message *message) {
if (IN_SET(link->state, LINK_STATE_PENDING, LINK_STATE_INITIALIZED, LINK_STATE_LINGER))
return 0;
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
if (r < 0)
return r;
data = new(ReconfigureData, 1);
if (!data)
return -ENOMEM;
r = netlink_call_async(link->manager->rtnl, NULL, req,
reconfigure_handler_on_bus_method_reload,
reconfigure_data_destroy_callback, data);
if (r < 0)
return r;
if (!data) {
r = -ENOMEM;
goto failed;
}
*data = (ReconfigureData) {
.link = link_ref(link),
@@ -1525,10 +1524,28 @@ int link_reconfigure_on_bus_method_reload(Link *link, sd_bus_message *message) {
.message = sd_bus_message_ref(message),
};
link->manager->reloading++;
r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
if (r < 0)
goto failed;
r = netlink_call_async(link->manager->rtnl, NULL, req,
reconfigure_handler_on_bus_method_reload,
reconfigure_data_destroy_callback, data);
if (r < 0)
goto failed;
TAKE_PTR(data);
link->manager->reloading++;
if (link->state == LINK_STATE_FAILED)
link_set_state(link, LINK_STATE_INITIALIZED);
return 0;
failed:
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
link_enter_failed(link);
return r;
}
static int link_initialized_and_synced(Link *link) {
+4 -13
View File
@@ -87,13 +87,8 @@ static int match_prepare_for_sleep(sd_bus_message *message, void *userdata, sd_b
log_debug("Coming back from suspend, reconfiguring all connections...");
HASHMAP_FOREACH(link, m->links_by_index) {
r = link_reconfigure(link, /* force = */ true);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure interface: %m");
link_enter_failed(link);
}
}
HASHMAP_FOREACH(link, m->links_by_index)
(void) link_reconfigure(link, /* force = */ true);
return 0;
}
@@ -1143,13 +1138,9 @@ int manager_reload(Manager *m, sd_bus_message *message) {
HASHMAP_FOREACH(link, m->links_by_index) {
if (message)
r = link_reconfigure_on_bus_method_reload(link, message);
(void) link_reconfigure_on_bus_method_reload(link, message);
else
r = link_reconfigure(link, /* force = */ false);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to reconfigure the interface: %m");
link_enter_failed(link);
}
(void) link_reconfigure(link, /* force = */ false);
}
r = 0;