[PATCH] device: allow for applying IPv4 and IPv6 settings in parallel



Hi,

We don't really need to wait before both IPv4 and IPv6 are established before
applying all the settings to the device. Instead, we can apply each separately
when they are ready, which will bring up the interface sooner.

Patch is attached; since it's relatively large.
---
 src/nm-device.c |  207 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 107 insertions(+), 100 deletions(-)

--
Mathieu Trudel-Lapierre <mathieu-tl ubuntu com>
Freenode: cyphermox, Jabber: mathieu tl gmail com
4096R/EE018C93 1967 8F7D 03A1 8F38 732E  FF82 C126 33E1 EE01 8C93
From 88ffb52bc20070bec0c88ebac76e562f3a14ed6e Mon Sep 17 00:00:00 2001
From: Mathieu Trudel-Lapierre <mathieu canonical com>
Date: Mon, 25 Jul 2011 17:43:48 -0400
Subject: [PATCH] device: allow for applying IPv4 and IPv6 settings in
 parallel

We don't really need to wait before both IPv4 and IPv6 are established before
applying all the settings to the device. Instead, we can apply each separately
when they are ready, which will bring up the interface sooner.
---
 src/nm-device.c |  207 ++++++++++++++++++++++++++++--------------------------
 1 files changed, 107 insertions(+), 100 deletions(-)

diff --git a/src/nm-device.c b/src/nm-device.c
index 1301197..fd837af 100644
--- a/src/nm-device.c
+++ b/src/nm-device.c
@@ -746,7 +746,7 @@ ip6_addrconf_complete (NMIP6Manager *ip6_manager,
 
 	/* Don't re-start DHCPv6 if it's already in progress */
 	state = nm_device_interface_get_state (NM_DEVICE_INTERFACE (self));
-	if ((state != NM_DEVICE_STATE_IP_CONFIG) || priv->dhcp6_client)
+	if ((state != NM_DEVICE_STATE_IP_CONFIG && state != NM_DEVICE_STATE_ACTIVATED) || priv->dhcp6_client)
 		return;
 
 	nm_log_info (LOGD_DEVICE | LOGD_DHCP6,
@@ -1346,6 +1346,67 @@ dhcp6_add_option_cb (gpointer key, gpointer value, gpointer user_data)
 	                            (const char *) value);
 }
 
+static void merge_dhcp_config_to_master (NMIP6Config *dst, NMIP6Config *src);
+
+static NMIP6Config *
+update_ip6_config_with_dhcp (NMDevice *device, NMIP6Config *ip6_config)
+{
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (device);
+	NMIP6Config *dhcp6_config;
+	NMActRequest *req;
+	NMConnection *connection;
+	NMSettingIP6Config *s_ip6;
+	NMDeviceStateReason reason = NM_DEVICE_STATE_REASON_NONE;
+	gboolean assumed, need_dhcp;
+
+	req = nm_device_get_act_request (device);
+	g_assert (req);
+	connection = nm_act_request_get_connection (req);
+	g_assert (connection);
+	assumed = nm_act_request_get_assumed (req);
+
+	if (   ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
+	    || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
+		need_dhcp = TRUE;
+	} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP)) {
+		need_dhcp = TRUE;
+		g_assert (priv->dhcp6_client);  /* sanity check */
+	}
+
+	if (need_dhcp) {
+		dhcp6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, TRUE);
+		if (!dhcp6_config) {
+			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_DHCP_ERROR);
+			return NULL;
+		}
+		if (!ip6_config && dhcp6_config)
+			ip6_config = dhcp6_config;
+		else
+			merge_dhcp_config_to_master (ip6_config, dhcp6_config);
+	}
+
+	s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
+	nm_utils_merge_ip6_config (ip6_config, s_ip6);
+
+	g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
+	g_object_notify (G_OBJECT (device), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
+
+	if (nm_device_set_ip6_config (device, ip6_config, assumed, &reason)) {
+		nm_log_warn (LOGD_IP6, "update_ip6_config_with_dhcp: 3 ; applied config");
+		nm_dhcp6_config_reset (priv->dhcp6_config);
+		nm_dhcp_client_foreach_option (priv->dhcp6_client,
+		                               dhcp6_add_option_cb,
+		                               priv->dhcp6_config);
+		nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL, NULL, NULL);
+	} else {
+		nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.",
+		             nm_device_get_ip_iface (device));
+		nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
+	}
+
+	return ip6_config;
+}
+
 static void
 handle_dhcp_lease_change (NMDevice *device, gboolean ipv6)
 {
@@ -1366,30 +1427,33 @@ handle_dhcp_lease_change (NMDevice *device, gboolean ipv6)
 	assumed = nm_act_request_get_assumed (req);
 
 	if (ipv6) {
-		ip6_config = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
+		if (   ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_AUTO)
+		    || ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) {
+			ip6_config = nm_ip6_manager_get_ip6_config (priv->ip6_manager,
+			                                         nm_device_get_ip_ifindex (device));
+			if (!ip6_config) {
+				nm_device_state_changed (device, NM_DEVICE_STATE_FAILED,
+				                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+				return;
+			}
+		} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_MANUAL)) {
+			ip6_config = nm_ip6_config_new ();
+			if (!ip6_config) {
+				nm_device_state_changed (device, NM_DEVICE_STATE_FAILED,
+				                         NM_DEVICE_STATE_REASON_IP_CONFIG_UNAVAILABLE);
+				return;
+			}
+		} else if (ip6_method_matches (connection, NM_SETTING_IP6_CONFIG_METHOD_DHCP))
+			g_assert (priv->dhcp6_client);  /* sanity check */
+
+		nm_log_warn (LOGD_DHCP6, "update_ip6_config_with_dhcp call");
+		ip6_config = update_ip6_config_with_dhcp (device, ip6_config);
 		if (!ip6_config) {
 			nm_log_warn (LOGD_DHCP6, "(%s): failed to get DHCPv6 config for rebind",
 			             nm_device_get_ip_iface (device));
 			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_IP_CONFIG_EXPIRED);
 			return;
 		}
-
-		s_ip6 = NM_SETTING_IP6_CONFIG (nm_connection_get_setting (connection, NM_TYPE_SETTING_IP6_CONFIG));
-		nm_utils_merge_ip6_config (ip6_config, s_ip6);
-
-		g_object_set_data (G_OBJECT (req), NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
-
-		if (nm_device_set_ip6_config (device, ip6_config, assumed, &reason)) {
-			nm_dhcp6_config_reset (priv->dhcp6_config);
-			nm_dhcp_client_foreach_option (priv->dhcp6_client,
-			                               dhcp6_add_option_cb,
-			                               priv->dhcp6_config);
-			nm_utils_call_dispatcher ("dhcp6-change", connection, device, NULL, NULL, NULL);
-		} else {
-			nm_log_warn (LOGD_DHCP6, "(%s): failed to update IPv6 config in response to DHCP event.",
-			             nm_device_get_ip_iface (device));
-			nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, reason);
-		}
 	} else {
 		ip4_config = nm_dhcp_client_get_ip4_config (priv->dhcp4_client, FALSE);
 		if (!ip4_config) {
@@ -1977,6 +2041,8 @@ real_act_stage4_get_ip4_config (NMDevice *self,
 	return ret;
 }
 
+static gboolean nm_device_activate_stage5_ip_config_commit (gpointer user_data);
+
 /*
  * nm_device_activate_stage4_ip4_config_get
  *
@@ -1987,6 +2053,7 @@ static gboolean
 nm_device_activate_stage4_ip4_config_get (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP4Config *ip4_config = NULL;
 	NMActStageReturn ret;
 	const char *iface = NULL;
@@ -2012,7 +2079,8 @@ nm_device_activate_stage4_ip4_config_get (gpointer user_data)
 	g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
 					   NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET);
+	priv->ip4_ready = TRUE;
+	nm_device_activate_stage5_ip_config_commit (self);
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP4,
@@ -2076,6 +2144,7 @@ static gboolean
 nm_device_activate_stage4_ip4_config_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP4Config *ip4_config = NULL;
 	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
@@ -2103,7 +2172,8 @@ nm_device_activate_stage4_ip4_config_timeout (gpointer user_data)
 						   NM_ACT_REQUEST_IP4_CONFIG, ip4_config);
 	}
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET);
+	priv->ip4_ready = TRUE;
+	nm_device_activate_stage5_ip_config_commit (self);
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP4,
@@ -2211,39 +2281,13 @@ real_act_stage4_get_ip6_config (NMDevice *self,
 
 	/* Autoconf might have triggered DHCPv6 too */
 	if (priv->dhcp6_client) {
-		NMIP6Config *dhcp;
-
-		dhcp = nm_dhcp_client_get_ip6_config (priv->dhcp6_client, FALSE);
-		if (!dhcp) {
+		*config = update_ip6_config_with_dhcp (self, *config);
+		if (!*config) {
+			nm_log_warn (LOGD_DHCP6, "(%s): failed to get DHCPv6 config for bind",
+			             nm_device_get_ip_iface (self));
 			*reason = NM_DEVICE_STATE_REASON_DHCP_ERROR;
 			goto out;
 		}
-
-		/* For "managed" and DHCP-only setups, we use only the DHCP-supplied
-		 * IPv6 config.  But when autoconf is enabled, we have to merge the
-		 * autoconf config and the DHCP-supplied config, then merge the
-		 * user's overrides from the connection to get the final configuration
-		 * that gets applied to the device.
-		 */
-		if (*config) {
-			/* Merge autoconf and DHCP configs */
-			merge_dhcp_config_to_master (*config, dhcp);
-			g_object_unref (dhcp);
-			dhcp = NULL;
-		} else {
-			*config = dhcp;
-		}
-
-		/* Copy the new DHCPv6 configuration into the DHCP config object that's
-		 * exported over D-Bus to clients.
-		 */
-		nm_dhcp6_config_reset (priv->dhcp6_config);
-		nm_dhcp_client_foreach_option (priv->dhcp6_client,
-		                               dhcp6_add_option_cb,
-		                               priv->dhcp6_config);
-
-		/* Notify of new DHCP6 config */
-		g_object_notify (G_OBJECT (self), NM_DEVICE_INTERFACE_DHCP6_CONFIG);
 	}
 
 	/* Merge user-defined overrides into the IP6Config to be applied */
@@ -2266,6 +2310,7 @@ static gboolean
 nm_device_activate_stage4_ip6_config_get (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP6Config *ip6_config = NULL;
 	NMActStageReturn ret;
 	const char *iface = NULL;
@@ -2292,7 +2337,8 @@ nm_device_activate_stage4_ip6_config_get (gpointer user_data)
 	g_object_set_data (G_OBJECT (nm_device_get_act_request (self)),
 					   NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6);
+	priv->ip6_ready = TRUE;
+	nm_device_activate_stage5_ip_config_commit (self);
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP6,
@@ -2356,6 +2402,7 @@ static gboolean
 nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
 {
 	NMDevice *self = NM_DEVICE (user_data);
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 	NMIP6Config *ip6_config = NULL;
 	const char *iface;
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE;
@@ -2383,7 +2430,8 @@ nm_device_activate_stage4_ip6_config_timeout (gpointer user_data)
 						   NM_ACT_REQUEST_IP6_CONFIG, ip6_config);
 	}
 
-	nm_device_activate_schedule_stage5_ip_config_commit (self, AF_INET6);
+	priv->ip6_ready = TRUE;
+	nm_device_activate_stage5_ip_config_commit (self);
 
 out:
 	nm_log_info (LOGD_DEVICE | LOGD_IP6,
@@ -2564,21 +2612,17 @@ nm_device_activate_stage5_ip_config_commit (gpointer user_data)
 	 * when automatic configuration changes (DHCP lease renewal, new
 	 * IPv6 router advertisement, etc), it's possible that only one of
 	 * them will be set.
+	 *
+	 * Also clear the activation source ID now that this stage has run.
 	 */
 	act_request = nm_device_get_act_request (self);
-
-	ip4_config = g_object_get_data (G_OBJECT (act_request),
+	if (priv->ip4_ready)
+		ip4_config = g_object_get_data (G_OBJECT (act_request),
 									NM_ACT_REQUEST_IP4_CONFIG);
-	g_object_set_data (G_OBJECT (act_request),
-					   NM_ACT_REQUEST_IP4_CONFIG, NULL);
 
-	ip6_config = g_object_get_data (G_OBJECT (act_request),
+	if (priv->ip6_ready)
+		ip6_config = g_object_get_data (G_OBJECT (act_request),
 									NM_ACT_REQUEST_IP6_CONFIG);
-	g_object_set_data (G_OBJECT (act_request),
-					   NM_ACT_REQUEST_IP6_CONFIG, NULL);
-
-	/* Clear the activation source ID now that this stage has run */
-	activation_source_clear (self, FALSE, 0);
 
 	iface = nm_device_get_iface (self);
 	nm_log_info (LOGD_DEVICE, "Activation (%s) Stage 5 of 5 (IP Configure Commit) started...",
@@ -2640,43 +2684,6 @@ out:
 	return FALSE;
 }
 
-
-/*
- * nm_device_activate_schedule_stage5_ip_config_commit
- *
- * Schedule commit of the IP config
- */
-static void
-nm_device_activate_schedule_stage5_ip_config_commit (NMDevice *self, int family)
-{
-	NMDevicePrivate *priv;
-
-	g_return_if_fail (NM_IS_DEVICE (self));
-
-	priv = NM_DEVICE_GET_PRIVATE (self);
-	g_return_if_fail (priv->act_request);
-
-	if (family == AF_INET)
-		priv->ip4_ready = TRUE;
-	else if (family == AF_INET6)
-		priv->ip6_ready = TRUE;
-
-	/* Note that these are only set FALSE at stage3, so once you've
-	 * made it all the way through activation once, you can jump back
-	 * into stage4 (eg, for a DHCP lease change) and not worry about
-	 * needing both IPv4 and IPv6 to complete.
-	 */
-	if (!priv->ip4_ready || !priv->ip6_ready)
-		return;
-
-	activation_source_schedule (self, nm_device_activate_stage5_ip_config_commit, 0);
-
-	nm_log_info (LOGD_DEVICE,
-	             "Activation (%s) Stage 5 of 5 (IP Configure Commit) scheduled...",
-	             nm_device_get_iface (self));
-}
-
-
 static void
 clear_act_request (NMDevice *self)
 {
-- 
Mathieu Trudel-Lapierre <mathieu trudel-lapierre canonical com>
Freenode: cyphermox, Jabber: mathieu tl gmail com
4096R/EE018C93 1967 8F7D 03A1 8F38 732E  FF82 C126 33E1 EE01 8C93



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]