summary refs log tree commit diff
path: root/src/devices/nm-device.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/nm-device.c')
-rw-r--r--src/devices/nm-device.c263
1 files changed, 148 insertions, 115 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 9df41410..5a5cb50e 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -280,11 +280,6 @@ typedef struct _NMDevicePrivate {
 
 	bool          real:1;
 
-	/* there was a IP config change, but no idle action was scheduled because device
-	 * is still not platform-init */
-	bool queued_ip4_config_pending:1;
-	bool queued_ip6_config_pending:1;
-
 	bool update_ip_config_completed_v4:1;
 	bool update_ip_config_completed_v6:1;
 
@@ -349,8 +344,9 @@ typedef struct _NMDevicePrivate {
 	gulong          config_changed_id;
 	guint32         mtu;
 	guint32         ip6_mtu;
-	guint32 mtu_initial;
-	guint32 ip6_mtu_initial;
+	guint32         mtu_initial;
+	guint32         ip6_mtu_initial;
+	NMDeviceMtuSource mtu_source;
 
 	guint32         v4_route_table;
 	guint32         v6_route_table;
@@ -366,8 +362,6 @@ typedef struct _NMDevicePrivate {
 	bool            carrier:1;
 	bool            ignore_carrier:1;
 
-	bool mtu_initialized:1;
-
 	bool            up:1;   /* IFF_UP */
 
 	bool            v4_commit_first_time:1;
@@ -735,6 +729,14 @@ NM_UTILS_LOOKUP_STR_DEFINE (nm_device_state_reason_to_str, NMDeviceStateReason,
 #define reason_to_string(reason) \
 	NM_UTILS_LOOKUP_STR (nm_device_state_reason_to_str, reason)
 
+NM_UTILS_LOOKUP_STR_DEFINE_STATIC (mtu_source_to_str, NMDeviceMtuSource,
+	NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT ("unknown"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_NONE,       "none"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_PARENT,     "parent"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_IP_CONFIG,  "ip-config"),
+	NM_UTILS_LOOKUP_STR_ITEM (NM_DEVICE_MTU_SOURCE_CONNECTION, "connection"),
+);
+
 /*****************************************************************************/
 
 NMSettings *
@@ -4001,7 +4003,7 @@ realize_start_setup (NMDevice *self,
 	/* Balanced by a thaw in nm_device_realize_finish() */
 	g_object_freeze_notify (G_OBJECT (self));
 
-	priv->mtu_initialized = FALSE;
+	priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE;
 	priv->mtu_initial = 0;
 	priv->ip6_mtu_initial = 0;
 	priv->ip6_mtu = 0;
@@ -4063,9 +4065,6 @@ realize_start_setup (NMDevice *self,
 		_notify (self, PROP_UDI);
 	}
 
-	priv->queued_ip4_config_pending = TRUE;
-	priv->queued_ip6_config_pending = TRUE;
-
 	nm_device_update_hw_address (self);
 	nm_device_update_initial_hw_address (self);
 	nm_device_update_permanent_hw_address (self, FALSE);
@@ -6822,7 +6821,9 @@ static gboolean
 dhcp4_grace_period_expired (gpointer user_data)
 {
 	NMDevice *self = user_data;
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
+	priv->dhcp4.grace_id = 0;
 	_LOGI (LOGD_DHCP4, "DHCPv4: grace period expired");
 
 	nm_device_ip_method_failed (self, AF_INET,
@@ -7553,7 +7554,9 @@ static gboolean
 dhcp6_grace_period_expired (gpointer user_data)
 {
 	NMDevice *self = user_data;
+	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
 
+	priv->dhcp6.grace_id = 0;
 	_LOGI (LOGD_DHCP6, "DHCPv6: grace period expired");
 
 	nm_device_ip_method_failed (self, AF_INET6,
@@ -7828,7 +7831,7 @@ generate_duid_from_machine_id (void)
 }
 
 static GBytes *
-dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcpDuidEnforce *out_enforce)
+dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, gboolean *out_enforce)
 {
 	NMSettingIPConfig *s_ip6;
 	const char *duid;
@@ -7837,7 +7840,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
 	GBytes *duid_out;
 	guint8 sha256_digest[32];
 	gsize len = sizeof (sha256_digest);
-	NMDhcpDuidEnforce duid_enforce = NM_DHCP_DUID_ENFORCE_ALWAYS;
+	gboolean duid_enforce = TRUE;
 	gs_free char *logstr1 = NULL;
 
 	s_ip6 = nm_connection_get_setting_ip6_config (connection);
@@ -7852,7 +7855,7 @@ dhcp6_get_duid (NMDevice *self, NMConnection *connection, GBytes *hwaddr, NMDhcp
 	}
 
 	if (nm_streq (duid, "lease")) {
-		duid_enforce = NM_DHCP_DUID_ENFORCE_NEVER;
+		duid_enforce = FALSE;
 		duid_out = generate_duid_from_machine_id ();
 		if (!duid_out) {
 			duid_error = "failure to read machine-id";
@@ -7972,7 +7975,7 @@ out_good:
 	       "ipv6.dhcp-duid: generate %s DUID '%s' (%s)",
 	       duid,
 	       (logstr1 = nm_dhcp_utils_duid_to_string (duid_out)),
-	       (duid_enforce == NM_DHCP_DUID_ENFORCE_ALWAYS) ? "enforcing" : "fallback");
+	       duid_enforce ? "enforcing" : "prefer lease");
 
 	NM_SET_OUT (out_enforce, duid_enforce);
 	return duid_out;
@@ -7985,7 +7988,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
 	NMSettingIPConfig *s_ip6;
 	gs_unref_bytes GBytes *hwaddr = NULL;
 	gs_unref_bytes GBytes *duid = NULL;
-	NMDhcpDuidEnforce enforce_duid = NM_DHCP_DUID_ENFORCE_NEVER;
+	gboolean enforce_duid = FALSE;
 
 	const NMPlatformIP6Address *ll_addr = NULL;
 
@@ -8371,40 +8374,68 @@ nm_device_get_configured_mtu_from_connection_default (NMDevice *self,
 }
 
 guint32
-nm_device_get_configured_mtu_for_wired (NMDevice *self, gboolean *out_is_user_config)
+nm_device_get_configured_mtu_from_connection (NMDevice *self,
+                                              GType setting_type,
+                                              NMDeviceMtuSource *out_source)
 {
+	const char *global_property_name;
 	NMConnection *connection;
-	NMSettingWired *setting;
+	NMSetting *setting;
 	gint64 mtu_default;
-	guint32 mtu;
+	guint32 mtu = 0;
 
 	nm_assert (NM_IS_DEVICE (self));
-	nm_assert (out_is_user_config);
+	nm_assert (out_source);
 
 	connection = nm_device_get_applied_connection (self);
 	if (!connection)
 		g_return_val_if_reached (0);
 
-	setting = nm_connection_get_setting_wired (connection);
+	setting = nm_connection_get_setting (connection, setting_type);
+
+	if (setting_type == NM_TYPE_SETTING_WIRED) {
+		if (setting)
+			mtu = nm_setting_wired_get_mtu (NM_SETTING_WIRED (setting));
+		global_property_name = "ethernet.mtu";
+	} else if (setting_type == NM_TYPE_SETTING_WIRELESS) {
+		if (setting)
+			mtu = nm_setting_wireless_get_mtu (NM_SETTING_WIRELESS (setting));
+		global_property_name = "wifi.mtu";
+	} else if (setting_type == NM_TYPE_SETTING_INFINIBAND) {
+		if (setting)
+			mtu = nm_setting_infiniband_get_mtu (NM_SETTING_INFINIBAND (setting));
+		global_property_name = "infiniband.mtu";
+	} else if (setting_type == NM_TYPE_SETTING_IP_TUNNEL) {
+		if (setting)
+			mtu = nm_setting_ip_tunnel_get_mtu (NM_SETTING_IP_TUNNEL (setting));
+		global_property_name = "ip-tunnel.mtu";
+	} else
+		g_return_val_if_reached (0);
 
-	if (setting) {
-		mtu = nm_setting_wired_get_mtu (setting);
-		if (mtu) {
-			*out_is_user_config = TRUE;
-			return mtu;
-		}
+
+	if (mtu) {
+		*out_source = NM_DEVICE_MTU_SOURCE_CONNECTION;
+		return mtu;
 	}
 
-	mtu_default = nm_device_get_configured_mtu_from_connection_default (self, "ethernet.mtu");
+	mtu_default = nm_device_get_configured_mtu_from_connection_default (self, global_property_name);
 	if (mtu_default >= 0) {
-		*out_is_user_config = TRUE;
+		*out_source = NM_DEVICE_MTU_SOURCE_CONNECTION;
 		return (guint32) mtu_default;
 	}
 
-	*out_is_user_config = FALSE;
+	*out_source = NM_DEVICE_MTU_SOURCE_NONE;
 	return 0;
 }
 
+guint32
+nm_device_get_configured_mtu_for_wired (NMDevice *self, NMDeviceMtuSource *out_source)
+{
+	return nm_device_get_configured_mtu_from_connection (self,
+	                                                     NM_TYPE_SETTING_WIRED,
+	                                                     out_source);
+}
+
 /*****************************************************************************/
 
 static void
@@ -8431,6 +8462,7 @@ static void
 _commit_mtu (NMDevice *self, const NMIP4Config *config)
 {
 	NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+	NMDeviceMtuSource source = NM_DEVICE_MTU_SOURCE_NONE;
 	guint32 ip6_mtu, ip6_mtu_orig;
 	guint32 mtu_desired, mtu_desired_orig;
 	guint32 mtu_plat;
@@ -8440,6 +8472,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 	} ip6_mtu_sysctl = { 0, };
 	int ifindex;
 	char sbuf[64], sbuf1[64], sbuf2[64];
+	gboolean success = TRUE;
 
 	ifindex = nm_device_get_ip_ifindex (self);
 	if (ifindex <= 0)
@@ -8453,7 +8486,6 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 	}
 
 	{
-		gboolean mtu_is_user_config = FALSE;
 		guint32 mtu = 0;
 
 		/* preferably, get the MTU from explict user-configuration.
@@ -8461,23 +8493,30 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 		 * MTUs from DHCP/PPP) or maybe fallback to a device-specific MTU. */
 
 		if (NM_DEVICE_GET_CLASS (self)->get_configured_mtu)
-			mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &mtu_is_user_config);
+			mtu = NM_DEVICE_GET_CLASS (self)->get_configured_mtu (self, &source);
+
+		if (   config
+		    && source < NM_DEVICE_MTU_SOURCE_IP_CONFIG
+		    && nm_ip4_config_get_mtu (config)) {
+			mtu = nm_ip4_config_get_mtu (config);
+			source = NM_DEVICE_MTU_SOURCE_IP_CONFIG;
+		}
+
+		if (mtu != 0) {
+			_LOGT (LOGD_DEVICE,
+			       "mtu: value %u from source '%s' (%u), current source '%s' (%u)",
+			       (guint) mtu,
+			       mtu_source_to_str (source), (guint) source,
+			       mtu_source_to_str (priv->mtu_source), (guint) priv->mtu_source);
+		}
 
-		if (mtu_is_user_config)
+		if (   mtu != 0
+		    && (   source > priv->mtu_source
+		        || (priv->mtu_source == NM_DEVICE_MTU_SOURCE_PARENT && source == priv->mtu_source)))
 			mtu_desired = mtu;
 		else {
-			if (config)
-				mtu_desired = nm_ip4_config_get_mtu (config);
-			else
-				mtu_desired = 0;
-			if (!mtu_desired && !priv->mtu_initialized) {
-				/* there is no MTU specified, and this is the first commit of the MTU.
-				 * Reset a per-device MTU default, as returned from get_configured_mtu().
-				 *
-				 * The device might choose not to return a default MTU via get_configured_mtu()
-				 * to suppress this behavior. */
-				mtu_desired = mtu;
-			}
+			mtu_desired = 0;
+			source = NM_DEVICE_MTU_SOURCE_NONE;
 		}
 	}
 
@@ -8499,7 +8538,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 	}
 
 	ip6_mtu = priv->ip6_mtu;
-	if (!ip6_mtu && !priv->mtu_initialized) {
+	if (!ip6_mtu && priv->mtu_source == NM_DEVICE_MTU_SOURCE_NONE) {
 		/* initially, if the IPv6 MTU is not specified, grow it as large as the
 		 * link MTU @mtu_desired. Only exception is, if @mtu_desired is so small
 		 * to disable IPv6. */
@@ -8507,8 +8546,6 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 			ip6_mtu = mtu_desired;
 	}
 
-	priv->mtu_initialized = TRUE;
-
 	if (!ip6_mtu && !mtu_desired)
 		return;
 
@@ -8560,6 +8597,7 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 		if (mtu_desired && mtu_desired != mtu_plat) {
 			if (nm_platform_link_set_mtu (nm_device_get_platform (self), ifindex, mtu_desired) == NM_PLATFORM_ERROR_CANT_SET_MTU) {
 				anticipated_failure = TRUE;
+				success = FALSE;
 				_LOGW (LOGD_DEVICE, "mtu: failure to set MTU. %s",
 				       NM_IS_DEVICE_VLAN (self)
 				         ? "Is the parent's MTU size large enough?"
@@ -8581,10 +8619,15 @@ _commit_mtu (NMDevice *self, const NMIP4Config *config)
 				        anticipated_failure && errsv == EINVAL
 				           ? ": Is the underlying MTU value successfully set?"
 				           : "");
+				success = FALSE;
 			}
 			priv->carrier_wait_until_ms = nm_utils_get_monotonic_timestamp_ms () + CARRIER_WAIT_TIME_AFTER_MTU_MS;
 		}
 	}
+
+	if (success && source != NM_DEVICE_MTU_SOURCE_NONE)
+		priv->mtu_source = source;
+
 #undef _IP6_MTU_SYS
 }
 
@@ -10178,13 +10221,13 @@ _cleanup_ip_pre (NMDevice *self, int addr_family, CleanupType cleanup_type)
 	}
 
 	if (IS_IPv4) {
-		priv->queued_ip4_config_pending = FALSE;
 		dhcp4_cleanup (self, cleanup_type, FALSE);
 		arp_cleanup (self);
 		dnsmasq_cleanup (self);
 		ipv4ll_cleanup (self);
 	} else {
-		priv->queued_ip6_config_pending = FALSE;
+		g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref);
+		priv->dad6_failed_addrs = NULL;
 		g_clear_object (&priv->dad6_ip6_config);
 		dhcp6_cleanup (self, cleanup_type, FALSE);
 		nm_clear_g_source (&priv->linklocal6_timeout_id);
@@ -12185,22 +12228,16 @@ static gboolean
 queued_ip_config_change (NMDevice *self, int addr_family)
 {
 	NMDevicePrivate *priv;
-	gboolean need_ipv6ll = FALSE;
 	const gboolean IS_IPv4 = (addr_family == AF_INET);
-	NMPlatform *platform;
 
 	g_return_val_if_fail (NM_IS_DEVICE (self), G_SOURCE_REMOVE);
 
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
-	nm_assert (IS_IPv4 ? !priv->queued_ip4_config_pending : !priv->queued_ip6_config_pending);
-
 	/* Wait for any queued state changes */
 	if (priv->queued_state.id)
 		return G_SOURCE_CONTINUE;
 
-	priv->queued_ip_config_id_x[IS_IPv4] = 0;
-
 	/* If a commit is scheduled, this function would potentially interfere with
 	 * it changing IP configurations before they are applied. Postpone the
 	 * update in such case.
@@ -12209,39 +12246,39 @@ queued_ip_config_change (NMDevice *self, int addr_family)
 	                                    IS_IPv4
 	                                      ? activate_stage5_ip4_config_result
 	                                      : activate_stage5_ip6_config_commit,
-	                                    addr_family)) {
-		if (IS_IPv4) {
-			priv->queued_ip4_config_pending = FALSE;
-			priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self);
-		} else {
-			priv->queued_ip6_config_pending = FALSE;
-			priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self);
-		}
-		_LOGT (LOGD_DEVICE, "IP%c update was postponed",
-		       nm_utils_addr_family_to_char (addr_family));
-	} else {
-		update_ip_config (self, addr_family);
+	                                    addr_family))
+		return G_SOURCE_CONTINUE;
 
-		if (!IS_IPv4) {
-			/* Check whether we need to complete waiting for link-local.
-			 * We are also called from an idle handler, so no problem doing state transitions
-			 * now. */
-			linklocal6_check_complete (self);
-		}
+	priv->queued_ip_config_id_x[IS_IPv4] = 0;
+
+	update_ip_config (self, addr_family);
+
+	if (!IS_IPv4) {
+		/* Check whether we need to complete waiting for link-local.
+		 * We are also called from an idle handler, so no problem doing state transitions
+		 * now. */
+		linklocal6_check_complete (self);
 	}
 
 	if (!IS_IPv4) {
-		if (   priv->state < NM_DEVICE_STATE_DEACTIVATING
+		NMPlatform *platform;
+		GSList *dad6_failed_addrs, *iter;
+
+		dad6_failed_addrs = g_steal_pointer (&priv->dad6_failed_addrs);
+
+		if (   priv->state > NM_DEVICE_STATE_DISCONNECTED
+		    && priv->state < NM_DEVICE_STATE_DEACTIVATING
+		    && !nm_device_sys_iface_state_is_external (self)
 		    && (platform = nm_device_get_platform (self))
 		    && nm_platform_link_get (platform, priv->ifindex)) {
+			gboolean need_ipv6ll = FALSE;
+			NMNDiscConfigMap ndisc_config_changed = NM_NDISC_CONFIG_NONE;
+
 			/* Handle DAD failures */
-			while (priv->dad6_failed_addrs) {
-				nm_auto_nmpobj const NMPObject *obj = NULL;
+			for (iter = dad6_failed_addrs; iter; iter = iter->next) {
+				const NMPObject *obj = iter->data;
 				const NMPlatformIP6Address *addr;
 
-				obj = priv->dad6_failed_addrs->data;
-				priv->dad6_failed_addrs = g_slist_delete_link (priv->dad6_failed_addrs, priv->dad6_failed_addrs);
-
 				if (!nm_ndisc_dad_addr_is_fail_candidate (platform, obj))
 					continue;
 
@@ -12253,9 +12290,12 @@ queued_ip_config_change (NMDevice *self, int addr_family)
 				if (IN6_IS_ADDR_LINKLOCAL (&addr->address))
 					need_ipv6ll = TRUE;
 				else if (priv->ndisc)
-					nm_ndisc_dad_failed (priv->ndisc, &addr->address);
+					ndisc_config_changed |= nm_ndisc_dad_failed (priv->ndisc, &addr->address, FALSE);
 			}
 
+			if (ndisc_config_changed != NM_NDISC_CONFIG_NONE)
+				nm_ndisc_emit_config_change (priv->ndisc, ndisc_config_changed);
+
 			/* If no IPv6 link-local address exists but other addresses do then we
 			 * must add the LL address to remain conformant with RFC 3513 chapter 2.1
 			 * ("Addressing Model"): "All interfaces are required to have at least
@@ -12264,14 +12304,14 @@ queued_ip_config_change (NMDevice *self, int addr_family)
 			if (   priv->ip_config_6
 			    && nm_ip6_config_get_num_addresses (priv->ip_config_6))
 				need_ipv6ll = TRUE;
-
 			if (need_ipv6ll)
 				check_and_add_ipv6ll_addr (self);
-		} else {
-			g_slist_free_full (priv->dad6_failed_addrs, (GDestroyNotify) nmp_object_unref);
-			priv->dad6_failed_addrs = NULL;
 		}
 
+		g_slist_free_full (dad6_failed_addrs, (GDestroyNotify) nmp_object_unref);
+	}
+
+	if (!IS_IPv4) {
 		/* Check if DAD is still pending */
 		if (   priv->ip6_state == IP_CONF
 		    && priv->dad6_ip6_config
@@ -12327,16 +12367,20 @@ device_ipx_changed (NMPlatform *platform,
 	if (nm_device_get_ip_ifindex (self) != ifindex)
 		return;
 
+	if (!nm_device_is_real (self))
+		return;
+
+	if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
+		/* ignore all platform signals until the link is initialized in platform. */
+		return;
+	}
+
 	priv = NM_DEVICE_GET_PRIVATE (self);
 
 	switch (obj_type) {
 	case NMP_OBJECT_TYPE_IP4_ADDRESS:
 	case NMP_OBJECT_TYPE_IP4_ROUTE:
-		if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
-			priv->queued_ip4_config_pending = TRUE;
-			nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4));
-		} else if (!priv->queued_ip_config_id_4) {
-			priv->queued_ip4_config_pending = FALSE;
+		if (!priv->queued_ip_config_id_4) {
 			priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self);
 			_LOGD (LOGD_DEVICE, "queued IP4 config change");
 		}
@@ -12350,13 +12394,10 @@ device_ipx_changed (NMPlatform *platform,
 			priv->dad6_failed_addrs = g_slist_prepend (priv->dad6_failed_addrs,
 			                                           (gpointer) nmp_object_ref (NMP_OBJECT_UP_CAST (addr)));
 		}
+
 		/* fall through */
 	case NMP_OBJECT_TYPE_IP6_ROUTE:
-		if (nm_device_get_unmanaged_flags (self, NM_UNMANAGED_PLATFORM_INIT)) {
-			priv->queued_ip6_config_pending = TRUE;
-			nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6));
-		} else if (!priv->queued_ip_config_id_6) {
-			priv->queued_ip6_config_pending = FALSE;
+		if (!priv->queued_ip_config_id_6) {
 			priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self);
 			_LOGD (LOGD_DEVICE, "queued IP6 config change");
 		}
@@ -12623,17 +12664,11 @@ _set_unmanaged_flags (NMDevice *self,
 			                               !!unmanaged);
 		}
 
-		if (priv->queued_ip4_config_pending) {
-			priv->queued_ip4_config_pending = FALSE;
-			nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4));
-			priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self);
-		}
-
-		if (priv->queued_ip6_config_pending) {
-			priv->queued_ip6_config_pending = FALSE;
-			nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6));
-			priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self);
-		}
+		/* trigger an initial update of IP configuration. */
+		nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_4));
+		nm_assert_se (!nm_clear_g_source (&priv->queued_ip_config_id_6));
+		priv->queued_ip_config_id_4 = g_idle_add (queued_ip4_config_change, self);
+		priv->queued_ip_config_id_6 = g_idle_add (queued_ip6_config_change, self);
 
 		if (!priv->pending_actions) {
 			do_notify_has_pending_actions = TRUE;
@@ -13623,7 +13658,7 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
 		NM_DEVICE_GET_CLASS (self)->deactivate_reset_hw_addr (self);
 	}
 
-	priv->mtu_initialized = FALSE;
+	priv->mtu_source = NM_DEVICE_MTU_SOURCE_NONE;
 	if (priv->mtu_initial || priv->ip6_mtu_initial) {
 		ifindex = nm_device_get_ip_ifindex (self);
 
@@ -13709,12 +13744,10 @@ nm_device_spawn_iface_helper (NMDevice *self)
 		g_ptr_array_add (argv, g_strdup_printf ("%d %s", (int) stable_type, stable_id));
 	}
 
-	logging_backend = nm_config_get_is_debug (nm_config_get ())
-	                  ? g_strdup ("debug")
-	                  : nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
-	                                              NM_CONFIG_KEYFILE_GROUP_LOGGING,
-	                                              NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
-	                                              NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
+	logging_backend = nm_config_data_get_value (NM_CONFIG_GET_DATA_ORIG,
+	                                            NM_CONFIG_KEYFILE_GROUP_LOGGING,
+	                                            NM_CONFIG_KEYFILE_KEY_LOGGING_BACKEND,
+	                                            NM_CONFIG_GET_VALUE_STRIP | NM_CONFIG_GET_VALUE_NO_EMPTY);
 	if (logging_backend) {
 		g_ptr_array_add (argv, g_strdup ("--logging-backend"));
 		g_ptr_array_add (argv, logging_backend);