diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6a8499f1b5..8d433d335d 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -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); diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 88548b122a..1fba2f51bb 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -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)) { diff --git a/src/core/dhcp/nm-dhcp-client.h b/src/core/dhcp/nm-dhcp-client.h index 3798f3b289..f779128ba3 100644 --- a/src/core/dhcp/nm-dhcp-client.h +++ b/src/core/dhcp/nm-dhcp-client.h @@ -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);