Merge pull request #34054 from yuwata/network-failed-state
network: several fixlets for reconfiguration after entered failed state
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user