device: preserve the DHCP lease during reapply

When the connection setting changes at the first place, then calling
the device reapply, the ip address got temporarily removed when DHCP
restarted. To avoid the ip address got temporarily removed, we should
preserve the previous lease and keep using it until the new lease comes
along.
This commit is contained in:
Wen Liang 2022-11-01 15:29:05 -04:00
parent f5cc21e9ec
commit 460b8392d7
3 changed files with 52 additions and 21 deletions

View file

@ -10419,6 +10419,8 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
no_lease_timeout_sec = _prop_get_ipvx_dhcp_timeout(self, addr_family);
previous_lease = priv->l3cds[L3_CONFIG_DATA_TYPE_DHCP_X(IS_IPv4)].d;
if (IS_IPv4) {
NMDhcpClientConfig config;
gs_unref_bytes GBytes *bcast_hwaddr = NULL;
@ -10465,6 +10467,7 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
.request_broadcast = request_broadcast,
.acd_timeout_msec = _prop_get_ipv4_dad_timeout(self),
},
.previous_lease = previous_lease,
};
priv->ipdhcp_data_4.client =
@ -10515,16 +10518,16 @@ _dev_ipdhcpx_start(NMDevice *self, int addr_family)
G_CALLBACK(_dev_ipdhcpx_notify),
self);
/* FIXME(l3cfg:dhcp:previous-lease): take the NML3ConfigData from the previous lease (if any)
* and pass it on to NMDhcpClient. This is a fake lease that we use initially (until
* NMDhcpClient got a real lease). Note that NMDhcpClient needs to check whether the
* lease already expired. */
/* Take the NML3ConfigData from the previous lease (if any) that was passed to the NMDhcpClient.
* This may be the old lease only used during the duration of a reapply until we get the
* new lease. */
previous_lease = nm_dhcp_client_get_lease(priv->ipdhcp_data_x[IS_IPv4].client);
if (!priv->ipdhcp_data_x[IS_IPv4].config) {
priv->ipdhcp_data_x[IS_IPv4].config = nm_dhcp_config_new(addr_family, previous_lease);
_notify(self, PROP_DHCPX_CONFIG(IS_IPv4));
}
if (previous_lease) {
nm_dhcp_config_set_lease(priv->ipdhcp_data_x[IS_IPv4].config, previous_lease);
_dev_l3_register_l3cds_set_one_full(self,
@ -12114,10 +12117,12 @@ activate_stage3_ip_config(NMDevice *self)
if (priv->ip_data_4.do_reapply) {
_LOGD_ip(AF_INET, "reapply...");
priv->ip_data_4.do_reapply = FALSE;
_cleanup_ip_pre(self, AF_INET, CLEANUP_TYPE_KEEP_REAPPLY);
}
if (priv->ip_data_6.do_reapply) {
_LOGD_ip(AF_INET6, "reapply...");
priv->ip_data_6.do_reapply = FALSE;
_cleanup_ip_pre(self, AF_INET6, CLEANUP_TYPE_KEEP_REAPPLY);
}
@ -12645,7 +12650,7 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type)
_dev_ipdev_cleanup(self, AF_UNSPEC);
_dev_ipdev_cleanup(self, addr_family);
_dev_ipdhcpx_cleanup(self, addr_family, TRUE, FALSE);
_dev_ipdhcpx_cleanup(self, addr_family, !keep_reapply, FALSE);
if (!IS_IPv4)
_dev_ipac6_cleanup(self);

View file

@ -84,6 +84,7 @@ typedef struct _NMDhcpClientPrivate {
* and is set from l3cd_next. */
const NML3ConfigData *l3cd_curr;
GSource *previous_lease_timeout_source;
GSource *no_lease_timeout_source;
GSource *watch_source;
GBytes *effective_client_id;
@ -237,6 +238,12 @@ nm_dhcp_client_create_l3cd(NMDhcpClient *self)
NM_IP_CONFIG_SOURCE_DHCP);
}
const NML3ConfigData *
nm_dhcp_client_get_lease(NMDhcpClient *self)
{
return NM_DHCP_CLIENT_GET_PRIVATE(self)->l3cd_curr;
}
/*****************************************************************************/
void
@ -828,6 +835,9 @@ _nm_dhcp_client_notify(NMDhcpClient *self,
return;
}
if (priv->l3cd_next)
nm_clear_g_source_inst(&priv->previous_lease_timeout_source);
nm_l3_config_data_reset(&priv->l3cd_curr, priv->l3cd_next);
if (client_event_type == NM_DHCP_CLIENT_EVENT_TYPE_BOUND && priv->l3cd_curr
@ -1299,6 +1309,19 @@ wait_dhcp_commit_done:
}
}
static gboolean
_previous_lease_timeout_cb(gpointer user_data)
{
NMDhcpClient *self = user_data;
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE(self);
nm_clear_g_source_inst(&priv->previous_lease_timeout_source);
_nm_dhcp_client_notify(self, NM_DHCP_CLIENT_EVENT_TYPE_TIMEOUT, NULL);
return G_SOURCE_CONTINUE;
}
gboolean
nm_dhcp_client_start(NMDhcpClient *self, GError **error)
{
@ -1336,6 +1359,14 @@ nm_dhcp_client_start(NMDhcpClient *self, GError **error)
_no_lease_timeout_schedule(self);
if (priv->config.previous_lease) {
/* We got passed a previous lease (during a reapply). For a few seconds, we
* will pretend that this is current lease. */
priv->l3cd_curr = g_steal_pointer(&priv->config.previous_lease);
priv->previous_lease_timeout_source =
nm_g_timeout_add_seconds_source(15, _previous_lease_timeout_cb, self);
}
if (IS_IPv4)
return NM_DHCP_CLIENT_GET_CLASS(self)->ip4_start(self, error);
@ -1416,6 +1447,8 @@ nm_dhcp_client_stop(NMDhcpClient *self, gboolean release)
if (priv->is_stopped)
return;
nm_clear_g_source_inst(&priv->previous_lease_timeout_source);
priv->is_stopped = TRUE;
if (priv->invocation) {
@ -1738,6 +1771,8 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src)
g_object_ref(config->l3cfg);
nm_l3_config_data_ref_and_seal(config->previous_lease);
nm_g_bytes_ref(config->hwaddr);
nm_g_bytes_ref(config->bcast_hwaddr);
nm_g_bytes_ref(config->vendor_class_identifier);
@ -1798,6 +1833,8 @@ config_clear(NMDhcpClientConfig *config)
{
g_object_unref(config->l3cfg);
nm_clear_l3cd(&config->previous_lease);
nm_clear_pointer(&config->hwaddr, g_bytes_unref);
nm_clear_pointer(&config->bcast_hwaddr, g_bytes_unref);
nm_clear_pointer(&config->vendor_class_identifier, g_bytes_unref);
@ -1874,6 +1911,7 @@ dispose(GObject *object)
watch_cleanup(self);
nm_clear_g_source_inst(&priv->previous_lease_timeout_source);
nm_clear_g_source_inst(&priv->no_lease_timeout_source);
if (!NM_IS_IPv4(priv->config.addr_family)) {

View file

@ -91,9 +91,8 @@ typedef struct {
* NMDhcpClient is supposed to run. */
NML3Cfg *l3cfg;
/* FIXME(l3cfg:dhcp:previous-lease): most parameters of NMDhcpClient are immutable,
* so to change them (during reapply), we need to create and start
* a new NMDhcpClient instance.
/* Most parameters of NMDhcpClient are immutable, so to change them (during
* reapply), we need to create and start a new NMDhcpClient instance.
*
* However, while the restart happens, we want to stick to the previous
* lease (if any). Allow the caller to provide such a previous lease,
@ -235,18 +234,7 @@ const NMDhcpClientConfig *nm_dhcp_client_get_config(NMDhcpClient *self);
pid_t nm_dhcp_client_get_pid(NMDhcpClient *self);
static inline const NML3ConfigData *
nm_dhcp_client_get_lease(NMDhcpClient *self)
{
/* FIXME(l3cfg:dhcp:previous-lease): this function returns the currently
* valid, exposed lease.
*
* Note that NMDhcpClient should accept as construct argument a *previous* lease,
* and (if that lease is still valid), pretend that it's good to use. The point is
* so that during reapply we keep using the current address, until a new lease
* was received. */
return NULL;
}
const NML3ConfigData *nm_dhcp_client_get_lease(NMDhcpClient *self);
void nm_dhcp_client_stop(NMDhcpClient *self, gboolean release);