From 455df69f0275726a4681e2e04c7b09545153e028 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Thu, 1 Aug 2013 15:44:53 -0500 Subject: [PATCH] core: fix handling of externally added IPv4 adresses and routes on IP change The switch to combine IPv4 configs to arrive at the final config would cause externally added addresses and routes to be removed from the interface when a DHCP or LLv4 event came in, becasue the externally added details weren't cached anywhere and thus would be dropped on the IP changes. --- src/devices/nm-device.c | 56 +++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 24 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 44bfe8c93e..9ca3661b8f 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -228,6 +228,7 @@ typedef struct { NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */ IpState ip4_state; NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ /* DHCPv4 tracking */ NMDHCPClient * dhcp4_client; @@ -303,6 +304,7 @@ static gboolean nm_device_set_ip4_config (NMDevice *dev, NMDeviceStateReason *reason); static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, + gboolean commit, NMDeviceStateReason *out_reason); static gboolean nm_device_set_ip6_config (NMDevice *dev, @@ -2102,7 +2104,7 @@ nm_device_handle_autoip4_event (NMDevice *self, aipd_timeout_remove (self); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - if (!ip4_config_merge_and_apply (self, config, &reason)) { + if (!ip4_config_merge_and_apply (self, config, TRUE, &reason)) { nm_log_err (LOGD_AUTOIP4, "(%s): failed to update IP4 config for autoip change.", nm_device_get_iface (self)); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); @@ -2274,6 +2276,7 @@ dhcp4_add_option_cb (gpointer key, gpointer value, gpointer user_data) static gboolean ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *config, + gboolean commit, NMDeviceStateReason *out_reason) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); @@ -2281,30 +2284,32 @@ ip4_config_merge_and_apply (NMDevice *self, gboolean success; NMIP4Config *composite; - connection = nm_device_get_connection (self); - g_assert (connection); - /* Merge all the configs into the composite config */ if (config) { g_clear_object (&priv->dev_ip4_config); priv->dev_ip4_config = g_object_ref (config); } - g_assert (priv->dev_ip4_config); - composite = nm_ip4_config_new (); - nm_ip4_config_merge (composite, priv->dev_ip4_config); + if (priv->dev_ip4_config) + nm_ip4_config_merge (composite, priv->dev_ip4_config); if (priv->vpn4_config) nm_ip4_config_merge (composite, priv->vpn4_config); + if (priv->ext_ip4_config) + nm_ip4_config_merge (composite, priv->ext_ip4_config); /* Merge user overrides into the composite config */ - nm_ip4_config_merge_setting (composite, nm_connection_get_setting_ip4_config (connection)); + connection = nm_device_get_connection (self); + if (connection) + nm_ip4_config_merge_setting (composite, nm_connection_get_setting_ip4_config (connection)); /* Allow setting MTU etc */ - if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) - NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); + if (commit) { + if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) + NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite); + } - success = nm_device_set_ip4_config (self, composite, TRUE, out_reason); + success = nm_device_set_ip4_config (self, composite, commit, out_reason); g_object_unref (composite); return success; } @@ -2316,7 +2321,7 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) g_return_if_fail (config != NULL); - if (!ip4_config_merge_and_apply (self, config, &reason)) { + if (!ip4_config_merge_and_apply (self, config, TRUE, &reason)) { nm_log_warn (LOGD_DHCP4, "(%s): failed to update IPv4 config for DHCP change.", nm_device_get_ip_iface (self)); nm_device_state_changed (self, NM_DEVICE_STATE_FAILED, reason); @@ -3780,7 +3785,7 @@ nm_device_activate_ip4_config_commit (gpointer user_data) nm_platform_link_set_up (ifindex); /* NULL to use the existing priv->dev_ip4_config */ - if (!ip4_config_merge_and_apply (self, NULL, &reason)) { + if (!ip4_config_merge_and_apply (self, NULL, TRUE, &reason)) { nm_log_info (LOGD_DEVICE | LOGD_IP4, "Activation (%s) Stage 5 of 5 (IPv4 Commit) failed", iface); @@ -4152,6 +4157,7 @@ nm_device_deactivate (NMDevice *self, NMDeviceStateReason reason) /* Clean up nameservers and addresses */ nm_device_set_ip4_config (self, NULL, TRUE, &ignored); nm_device_set_ip6_config (self, NULL, TRUE, &ignored); + g_clear_object (&priv->ext_ip4_config); g_clear_object (&priv->vpn4_config); g_clear_object (&priv->vpn6_config); @@ -4423,7 +4429,7 @@ nm_device_set_vpn4_config (NMDevice *device, NMIP4Config *config) priv->vpn4_config = g_object_ref (config); /* NULL to use existing configs */ - if (!ip4_config_merge_and_apply (device, NULL, NULL)) { + if (!ip4_config_merge_and_apply (device, NULL, TRUE, NULL)) { nm_log_warn (LOGD_IP4, "(%s): failed to set VPN routes for device", nm_device_get_ip_iface (device)); } @@ -4846,6 +4852,7 @@ dispose (GObject *object) nm_device_take_down (self, FALSE); } g_clear_object (&priv->dev_ip4_config); + g_clear_object (&priv->ext_ip4_config); g_clear_object (&priv->vpn4_config); g_clear_object (&priv->ip4_config); @@ -5933,8 +5940,7 @@ update_ip_config (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDeviceStateReason ignored = NM_DEVICE_STATE_REASON_NONE; - NMIP4Config *ip4_config; - NMIP6Config *ip6_config; + NMIP6Config *ip6_config = NULL; int ifindex; if (priv->state != NM_DEVICE_STATE_UNMANAGED) @@ -5944,16 +5950,18 @@ update_ip_config (NMDevice *self) if (!ifindex) return; - ip4_config = nm_ip4_config_capture (ifindex); + g_clear_object (&priv->ext_ip4_config); + priv->ext_ip4_config = nm_ip4_config_capture (ifindex); + if (priv->dev_ip4_config) + nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config); + if (priv->vpn4_config) + nm_ip4_config_subtract (priv->ext_ip4_config, priv->vpn4_config); + + ip4_config_merge_and_apply (self, NULL, FALSE, NULL); + ip6_config = nm_ip6_config_capture (ifindex); - - nm_device_set_ip4_config (self, ip4_config, FALSE, &ignored); nm_device_set_ip6_config (self, ip6_config, FALSE, &ignored); - - if (ip4_config) - g_object_unref (ip4_config); - if (ip6_config) - g_object_unref (ip6_config); + g_clear_object (&ip6_config); } static gboolean