summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-11-21 13:13:48 +0100
committerThomas Haller <thaller@redhat.com>2015-01-24 18:27:12 +0100
commit557667df12fc05b76326d6406553985effeeb2ac (patch)
tree5a24b8533f6679769f4aa3e0a711f3e8907c52fa
parent2c0644908524b6d9256d377b28194ba3d10535d5 (diff)
downloadNetworkManager-557667df12fc05b76326d6406553985effeeb2ac.tar.gz
device: better accept external IP changes
When receiving IP changes via platform event, remove all missing addresses and routes from our internal configurations (such as wwan, vpn, dhcp). The effect is that on the next commit, those addresses and routes will not be re-added as they were explicitly removed by the user. However on a new DHCP lease or similar events, the addresses will be added anew. Another important improvement is that the NMIPxConfig of the active device reflects when addresses or routes get removed externally. Before we would continue to expose those entires although they were not actually configured on the device. https://bugzilla.gnome.org/show_bug.cgi?id=740443
-rw-r--r--src/devices/nm-device.c134
1 files changed, 100 insertions, 34 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 7219b0616b..77aaedbac7 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -239,9 +239,9 @@ typedef struct {
/* IP4 configuration info */
NMIP4Config * ip4_config; /* Combined config from VPN, settings, and device */
IpState ip4_state;
+ NMIP4Config * con_ip4_config; /* config from the setting */
NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
- gboolean ext_ip4_config_had_any_addresses;
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
struct {
gboolean v4_has;
@@ -276,10 +276,10 @@ typedef struct {
/* IP6 configuration info */
NMIP6Config * ip6_config;
IpState ip6_state;
+ NMIP6Config * con_ip6_config; /* config from the setting */
NMIP6Config * vpn6_config; /* routes added by a VPN which uses this device */
NMIP6Config * wwan_ip6_config;
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
- gboolean ext_ip6_config_had_any_addresses;
gboolean nm_ipv6ll; /* TRUE if NM handles the device's IPv6LL address */
NMRDisc * rdisc;
@@ -2836,6 +2836,43 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat
}
/*********************************************/
+
+static void
+ensure_con_ipx_config (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMConnection *connection;
+
+ g_assert (!!priv->con_ip4_config == !!priv->con_ip6_config);
+
+ if (priv->con_ip4_config)
+ return;
+
+ connection = nm_device_get_connection (self);
+ if (!connection)
+ return;
+
+ priv->con_ip4_config = nm_ip4_config_new ();
+ priv->con_ip6_config = nm_ip6_config_new ();
+
+ nm_ip4_config_merge_setting (priv->con_ip4_config,
+ nm_connection_get_setting_ip4_config (connection),
+ nm_device_get_ip4_route_metric (self));
+ nm_ip6_config_merge_setting (priv->con_ip6_config,
+ nm_connection_get_setting_ip6_config (connection),
+ nm_device_get_ip6_route_metric (self));
+
+ if (nm_device_uses_assumed_connection (self)) {
+ /* For assumed connections ignore all addresses and routes. */
+ nm_ip4_config_reset_addresses (priv->con_ip4_config);
+ nm_ip4_config_reset_routes (priv->con_ip4_config);
+
+ nm_ip6_config_reset_addresses (priv->con_ip6_config);
+ nm_ip6_config_reset_routes (priv->con_ip6_config);
+ }
+}
+
+/*********************************************/
/* DHCPv4 stuff */
static void
@@ -2884,6 +2921,9 @@ ip4_config_merge_and_apply (NMDevice *self,
}
composite = nm_ip4_config_new ();
+
+ ensure_con_ipx_config (self);
+
if (priv->dev_ip4_config)
nm_ip4_config_merge (composite, priv->dev_ip4_config);
if (priv->vpn4_config)
@@ -2897,17 +2937,12 @@ ip4_config_merge_and_apply (NMDevice *self,
if (priv->wwan_ip4_config)
nm_ip4_config_merge (composite, priv->wwan_ip4_config);
- /* Merge user overrides into the composite config. Generated+assumed
- * connections come from the system not the user and merging them would
- * be redundant, so don't bother.
- */
+ /* Merge user overrides into the composite config. For assumed connection,
+ * con_ip4_config is empty. */
+ if (priv->con_ip4_config)
+ nm_ip4_config_merge (composite, priv->con_ip4_config);
+
connection = nm_device_get_connection (self);
- if ( connection
- && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
- nm_ip4_config_merge_setting (composite,
- nm_connection_get_setting_ip4_config (connection),
- default_route_metric);
- }
/* Add the default route.
*
@@ -2935,8 +2970,7 @@ ip4_config_merge_and_apply (NMDevice *self,
priv->default_route.v4_is_assumed = FALSE;
- if ( !(!commit && priv->ext_ip4_config_had_any_addresses)
- && !( commit && nm_ip4_config_get_num_addresses (composite))) {
+ if (!nm_ip4_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
@@ -3454,7 +3488,8 @@ ip6_config_merge_and_apply (NMDevice *self,
/* If no config was passed in, create a new one */
composite = nm_ip6_config_new ();
- g_assert (composite);
+
+ ensure_con_ipx_config (self);
/* Merge all the IP configs into the composite config */
if (priv->ac_ip6_config)
@@ -3472,17 +3507,12 @@ ip6_config_merge_and_apply (NMDevice *self,
if (priv->wwan_ip6_config)
nm_ip6_config_merge (composite, priv->wwan_ip6_config);
- /* Merge user overrides into the composite config. Generated+assumed
- * connections come from the system not the user and merging them would
- * be redundant, so don't bother.
- */
+ /* Merge user overrides into the composite config. For assumed connections,
+ * con_ip6_config is empty. */
+ if (priv->con_ip6_config)
+ nm_ip6_config_merge (composite, priv->con_ip6_config);
+
connection = nm_device_get_connection (self);
- if ( connection
- && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) {
- nm_ip6_config_merge_setting (composite,
- nm_connection_get_setting_ip6_config (connection),
- nm_device_get_ip6_route_metric (self));
- }
/* Add the default route.
*
@@ -3510,8 +3540,7 @@ ip6_config_merge_and_apply (NMDevice *self,
priv->default_route.v6_is_assumed = FALSE;
- if ( !(!commit && priv->ext_ip6_config_had_any_addresses)
- && !( commit && nm_ip6_config_get_num_addresses (composite))) {
+ if (!nm_ip6_config_get_num_addresses (composite)) {
/* without addresses we can have no default route. */
goto END_ADD_DEFAULT_ROUTE;
}
@@ -6523,13 +6552,31 @@ update_ip_config (NMDevice *self, gboolean initial)
/* IPv4 */
g_clear_object (&priv->ext_ip4_config);
priv->ext_ip4_config = nm_ip4_config_capture (ifindex, capture_resolv_conf);
- priv->ext_ip4_config_had_any_addresses = ( priv->ext_ip4_config
- && nm_ip4_config_get_num_addresses (priv->ext_ip4_config) > 0);
if (priv->ext_ip4_config) {
if (initial) {
g_clear_object (&priv->dev_ip4_config);
capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL);
}
+ ensure_con_ipx_config (self);
+
+ /* This function was called upon external changes. Remove the configuration
+ * (adresses,routes) that is no longer present externally from the interal
+ * config. This way, we don't readd addresses that were manually removed
+ * by the user. */
+ if (priv->con_ip4_config)
+ nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config);
+ if (priv->dev_ip4_config)
+ nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config);
+ if (priv->vpn4_config)
+ nm_ip4_config_intersect (priv->vpn4_config, priv->ext_ip4_config);
+ if (priv->wwan_ip4_config)
+ nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config);
+
+ /* Remove parts from ext_ip4_config to only contain the information that
+ * was configured externally -- we already have the same configuration from
+ * internal origins. */
+ if (priv->con_ip4_config)
+ nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config);
if (priv->dev_ip4_config)
nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config);
if (priv->vpn4_config)
@@ -6543,14 +6590,34 @@ update_ip_config (NMDevice *self, gboolean initial)
/* IPv6 */
g_clear_object (&priv->ext_ip6_config);
priv->ext_ip6_config = nm_ip6_config_capture (ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
- priv->ext_ip6_config_had_any_addresses = ( priv->ext_ip6_config
- && nm_ip6_config_get_num_addresses (priv->ext_ip6_config) > 0);
if (priv->ext_ip6_config) {
/* Check this before modifying ext_ip6_config */
linklocal6_just_completed = priv->linklocal6_timeout_id &&
have_ip6_address (priv->ext_ip6_config, TRUE);
+ ensure_con_ipx_config (self);
+
+ /* This function was called upon external changes. Remove the configuration
+ * (adresses,routes) that is no longer present externally from the interal
+ * config. This way, we don't readd addresses that were manually removed
+ * by the user. */
+ if (priv->con_ip6_config)
+ nm_ip6_config_intersect (priv->con_ip6_config, priv->ext_ip6_config);
+ if (priv->ac_ip6_config)
+ nm_ip6_config_intersect (priv->ac_ip6_config, priv->ext_ip6_config);
+ if (priv->dhcp6_ip6_config)
+ nm_ip6_config_intersect (priv->dhcp6_ip6_config, priv->ext_ip6_config);
+ if (priv->wwan_ip6_config)
+ nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config);
+ if (priv->vpn6_config)
+ nm_ip6_config_intersect (priv->vpn6_config, priv->ext_ip6_config);
+
+ /* Remove parts from ext_ip6_config to only contain the information that
+ * was configured externally -- we already have the same configuration from
+ * internal origins. */
+ if (priv->con_ip6_config)
+ nm_ip6_config_subtract (priv->ext_ip6_config, priv->con_ip6_config);
if (priv->ac_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config);
if (priv->dhcp6_ip6_config)
@@ -7142,20 +7209,19 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure)
*/
nm_device_set_ip4_config (self, NULL, 0, TRUE, &ignored);
nm_device_set_ip6_config (self, NULL, TRUE, &ignored);
+ g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->dev_ip4_config);
g_clear_object (&priv->ext_ip4_config);
g_clear_object (&priv->wwan_ip4_config);
g_clear_object (&priv->vpn4_config);
g_clear_object (&priv->ip4_config);
+ g_clear_object (&priv->con_ip6_config);
g_clear_object (&priv->ac_ip6_config);
g_clear_object (&priv->ext_ip6_config);
g_clear_object (&priv->vpn6_config);
g_clear_object (&priv->wwan_ip6_config);
g_clear_object (&priv->ip6_config);
- priv->ext_ip4_config_had_any_addresses = FALSE;
- priv->ext_ip6_config_had_any_addresses = FALSE;
-
clear_act_request (self);
/* Clear legacy IPv4 address property */