From cf4e2c7ab9116cc7c2681d04fe7dac51c7a4555c Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Thu, 7 Apr 2016 15:09:54 +0200 Subject: [PATCH] device: retry DHCPv6 when a lease expires Make DHCPv6 more robust WRT temporary failures of servers by retrying DHCP for a predefined number of times at regular intervals when the lease expires. https://bugzilla.gnome.org/show_bug.cgi?id=741347 --- src/devices/nm-device.c | 38 ++++++++++++++++++++++++++++++-------- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 74d8f9eea7..e645682e87 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -356,6 +356,7 @@ typedef struct _NMDevicePrivate { /* Event ID of the current IP6 config from DHCP */ char * event_id; guint restart_id; + guint num_tries_left; } dhcp6; /* allow autoconnect feature */ @@ -5316,8 +5317,10 @@ dhcp6_restart_cb (gpointer user_data) priv = NM_DEVICE_GET_PRIVATE (self); priv->dhcp6.restart_id = 0; - if (!dhcp6_start (self, FALSE, &reason)) - priv->dhcp6.restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self); + if (!dhcp6_start (self, FALSE, &reason)) { + priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, + dhcp6_restart_cb, self); + } return FALSE; } @@ -5327,6 +5330,9 @@ dhcp6_fail (NMDevice *self, gboolean timeout) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + _LOGD (LOGD_DHCP6, "DHCPv6 failed: timeout %d, num tries left %u", + timeout, priv->dhcp6.num_tries_left); + dhcp6_cleanup (self, CLEANUP_TYPE_DECONFIGURE, FALSE); if (priv->dhcp6.mode == NM_RDISC_DHCP_LEVEL_MANAGED) { @@ -5337,7 +5343,8 @@ dhcp6_fail (NMDevice *self, gboolean timeout) && priv->con_ip6_config && nm_ip6_config_get_num_addresses (priv->con_ip6_config)) { _LOGI (LOGD_DHCP6, "Scheduling DHCPv6 restart because device has IP addresses"); - priv->dhcp6.restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self); + priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, + dhcp6_restart_cb, self); return; } @@ -5347,15 +5354,27 @@ dhcp6_fail (NMDevice *self, gboolean timeout) */ if (nm_device_uses_assumed_connection (self)) { _LOGI (LOGD_DHCP6, "Scheduling DHCPv6 restart because the connection is assumed"); - priv->dhcp6.restart_id = g_timeout_add_seconds (120, dhcp6_restart_cb, self); + priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, + dhcp6_restart_cb, self); return; } - if (timeout || (priv->ip6_state == IP_CONF)) + if ( priv->dhcp6.num_tries_left == DHCP_NUM_TRIES_MAX + && (timeout || (priv->ip6_state == IP_CONF))) nm_device_activate_schedule_ip6_config_timeout (self); - else if (priv->ip6_state == IP_DONE) - nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); - else + else if (priv->ip6_state == IP_DONE) { + /* Don't fail immediately when the lease expires but try to + * restart DHCP for a predefined number of times. + */ + if (priv->dhcp6.num_tries_left) { + _LOGI (LOGD_DHCP6, "restarting DHCPv6 in %d seconds (%u tries left)", + DHCP_RESTART_TIMEOUT, priv->dhcp6.num_tries_left); + priv->dhcp6.restart_id = g_timeout_add_seconds (DHCP_RESTART_TIMEOUT, + dhcp6_restart_cb, self); + priv->dhcp6.num_tries_left--; + } else + nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED); + } else g_warn_if_reached (); } else { /* not a hard failure; just live with the RA info */ @@ -5421,6 +5440,8 @@ dhcp6_state_changed (NMDhcpClient *client, } } + priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX; + if (priv->ip6_state == IP_CONF) { if (priv->dhcp6.ip6_config == NULL) { nm_device_ip_method_failed (self, AF_INET6, NM_DEVICE_STATE_REASON_DHCP_FAILED); @@ -6282,6 +6303,7 @@ act_stage3_ip6_config_start (NMDevice *self, } priv->dhcp6.mode = NM_RDISC_DHCP_LEVEL_NONE; + priv->dhcp6.num_tries_left = DHCP_NUM_TRIES_MAX; method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG);