diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2017-11-17 16:39:40 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2017-12-06 09:53:18 +0100 |
commit | 7217ec09e34324e14a0a9d8b519e9cc1aa2b98b4 (patch) | |
tree | 7b9905ab8a323ddf9dc8ceeba25f741255f054db | |
parent | 898b978e365a94b5c5caf2ab17b014fbc0b1cb33 (diff) | |
download | NetworkManager-7217ec09e34324e14a0a9d8b519e9cc1aa2b98b4.tar.gz |
device: restore original dynamic IPv4 configuration on reapply
The dynamic IPv4 configuration from DHCP/PPP/... and WWAN is stored in
priv->{dev,wwan}_ip4_config; when the user removes externally an
address or a route, we prune it from those configurations. Therefore
such addresses and routes can't be restored on a device reapply.
Introduce an AppliedConfig structure that stores both the original and
the current (after external changes) configuration so that we can
restore the original one on reapply.
-rw-r--r-- | src/devices/nm-device.c | 131 |
1 files changed, 88 insertions, 43 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index beda3b518d..d24d02765c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -152,6 +152,12 @@ typedef enum { FIREWALL_STATE_WAIT_IP_CONFIG, } FirewallState; +typedef struct { + NMIPConfig *orig; /* the original configuration applied to the device */ + NMIPConfig *current; /* configuration after external changes. NULL means + that the original configuration didn't change. */ +} AppliedConfig; + /*****************************************************************************/ enum { @@ -373,9 +379,9 @@ typedef struct _NMDevicePrivate { IpState ip4_state_; }; NMIP4Config * con_ip4_config; /* config from the setting */ - NMIP4Config * dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + AppliedConfig dev_ip4_config; /* Config from DHCP, PPP, LLv4, etc */ + AppliedConfig wwan_ip4_config; /* WWAN configuration */ NMIP4Config * ext_ip4_config; /* Stuff added outside NM */ - NMIP4Config * wwan_ip4_config; /* WWAN configuration */ GSList * vpn4_configs; /* VPNs which use this device */ bool v4_has_shadowed_routes; @@ -695,6 +701,27 @@ _ip6_config_new (NMDevice *self) nm_device_get_ip_ifindex (self)); } +static void +applied_config_clear (AppliedConfig *config) +{ + g_clear_object (&config->current); + g_clear_object (&config->orig); +} + +static void +applied_config_init (AppliedConfig *config, gpointer ip_config) +{ + nm_g_object_ref (ip_config); + applied_config_clear (config); + config->orig = ip_config; +} + +static NMIPConfig * +applied_config_get_current (AppliedConfig *config) +{ + return config->current ?: config->orig; +} + /*****************************************************************************/ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_sys_iface_state_to_str, NMDeviceSysIfaceState, @@ -5625,8 +5652,7 @@ nm_device_handle_ipv4ll_event (sd_ipv4ll *ll, int event, void *data) nm_clear_g_source (&priv->ipv4ll_timeout); nm_device_activate_schedule_ip4_config_result (self, config); } else if (priv->ip4_state == IP_DONE) { - g_clear_object (&priv->dev_ip4_config); - priv->dev_ip4_config = g_object_ref (config); + applied_config_init (&priv->dev_ip4_config, config); if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGE (LOGD_AUTOIP4, "failed to update IP4 config for autoip change."); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_AUTOIP_FAILED); @@ -5811,7 +5837,7 @@ ip4_config_merge_and_apply (NMDevice *self, NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMConnection *connection; gboolean success; - NMIP4Config *composite; + NMIP4Config *composite, *config; gboolean ignore_auto_routes = FALSE; gboolean ignore_auto_dns = FALSE; gboolean ignore_default_routes = FALSE; @@ -5849,8 +5875,9 @@ ip4_config_merge_and_apply (NMDevice *self, if (commit) priv->default_route_metric_penalty_ip4_has = default_route_metric_penalty_detect (self); - if (priv->dev_ip4_config) { - nm_ip4_config_merge (composite, priv->dev_ip4_config, + config = (NMIP4Config *) applied_config_get_current (&priv->dev_ip4_config); + if (config) { + nm_ip4_config_merge (composite, config, (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), @@ -5866,8 +5893,9 @@ ip4_config_merge_and_apply (NMDevice *self, /* Merge WWAN config *last* to ensure modem-given settings overwrite * any external stuff set by pppd or other scripts. */ - if (priv->wwan_ip4_config) { - nm_ip4_config_merge (composite, priv->wwan_ip4_config, + config = (NMIP4Config *) applied_config_get_current (&priv->wwan_ip4_config); + if (config) { + nm_ip4_config_merge (composite, config, (ignore_auto_routes ? NM_IP_CONFIG_MERGE_NO_ROUTES : 0) | (ignore_default_routes ? NM_IP_CONFIG_MERGE_NO_DEFAULT_ROUTES : 0) | (ignore_auto_dns ? NM_IP_CONFIG_MERGE_NO_DNS : 0), @@ -5908,8 +5936,7 @@ dhcp4_lease_change (NMDevice *self, NMIP4Config *config) g_return_val_if_fail (config, FALSE); - g_clear_object (&priv->dev_ip4_config); - priv->dev_ip4_config = g_object_ref (config); + applied_config_init (&priv->dev_ip4_config, config); if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGW (LOGD_DHCP4, "failed to update IPv4 config for DHCP change."); @@ -8578,7 +8605,6 @@ activate_stage5_ip4_config_result (NMDevice *self) _LOGW (LOGD_DEVICE, "interface %s not up for IP configuration", nm_device_get_ip_iface (self)); } - /* NULL to use the existing priv->dev_ip4_config */ if (!ip4_config_merge_and_apply (self, TRUE)) { _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Commit) failed"); nm_device_ip_method_failed (self, AF_INET, NM_DEVICE_STATE_REASON_CONFIG_FAILED); @@ -8627,10 +8653,7 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf g_return_if_fail (NM_IS_DEVICE (self)); priv = NM_DEVICE_GET_PRIVATE (self); - g_clear_object (&priv->dev_ip4_config); - if (config) - priv->dev_ip4_config = g_object_ref (config); - + applied_config_init (&priv->dev_ip4_config, config); activation_source_schedule (self, activate_stage5_ip4_config_result, AF_INET); } @@ -9107,6 +9130,8 @@ nm_device_reactivate_ip4_config (NMDevice *self, if (priv->ip4_state != IP_NONE) { g_clear_object (&priv->con_ip4_config); g_clear_object (&priv->ext_ip4_config); + g_clear_object (&priv->dev_ip4_config.current); + g_clear_object (&priv->wwan_ip4_config.current); priv->con_ip4_config = _ip4_config_new (self); nm_ip4_config_merge_setting (priv->con_ip4_config, s_ip4_new, @@ -10144,7 +10169,7 @@ nm_device_set_ip4_config (NMDevice *self, _LOGD (LOGD_IP4, "ip4-config: clear IP4Config instance (%s)", nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config))); /* Device config is invalid if combined config is invalid */ - g_clear_object (&priv->dev_ip4_config); + applied_config_clear (&priv->dev_ip4_config); } concheck_periodic_update (self); @@ -10242,14 +10267,7 @@ nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - if (priv->wwan_ip4_config == config) - return; - - g_clear_object (&priv->wwan_ip4_config); - if (config) - priv->wwan_ip4_config = g_object_ref (config); - - /* NULL to use existing configs */ + applied_config_init (&priv->wwan_ip4_config, config); if (!ip4_config_merge_and_apply (self, TRUE)) _LOGW (LOGD_IP4, "failed to set WWAN IPv4 configuration"); } @@ -10970,6 +10988,32 @@ capture_lease_config (NMDevice *self, } } +static void +intersect_ext_config (NMDevice *self, AppliedConfig *config) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMIPConfig *ext; + guint32 penalty; + int family; + + if (!config->orig) + return; + + family = nm_ip_config_get_addr_family (config->orig); + penalty = default_route_metric_penalty_get (self, family); + ext = family == AF_INET + ? (NMIPConfig *) priv->ext_ip4_config + : (NMIPConfig *) priv->ext_ip6_config; + + if (config->current) + nm_ip_config_intersect (config->current, ext, penalty); + else { + config->current = nm_ip_config_intersect_alloc (config->orig, + ext, + penalty); + } +} + static gboolean update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolean intersect_configs) { @@ -10996,8 +11040,11 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolea capture_resolv_conf); 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); + applied_config_clear (&priv->dev_ip4_config); + capture_lease_config (self, + priv->ext_ip4_config, + (NMIP4Config **) &priv->dev_ip4_config.orig, + NULL, NULL); } if (intersect_configs) { @@ -11009,14 +11056,10 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolea nm_ip4_config_intersect (priv->con_ip4_config, priv->ext_ip4_config, default_route_metric_penalty_get (self, AF_INET)); } - if (priv->dev_ip4_config) { - nm_ip4_config_intersect (priv->dev_ip4_config, priv->ext_ip4_config, - default_route_metric_penalty_get (self, AF_INET)); - } - if (priv->wwan_ip4_config) { - nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config, - default_route_metric_penalty_get (self, AF_INET)); - } + + intersect_ext_config (self, &priv->dev_ip4_config); + intersect_ext_config (self, &priv->wwan_ip4_config); + for (iter = priv->vpn4_configs; iter; iter = iter->next) nm_ip4_config_intersect (iter->data, priv->ext_ip4_config, 0); } @@ -11028,13 +11071,15 @@ update_ext_ip_config (NMDevice *self, int addr_family, gboolean initial, gboolea nm_ip4_config_subtract (priv->ext_ip4_config, priv->con_ip4_config, default_route_metric_penalty_get (self, AF_INET)); } - if (priv->dev_ip4_config) { - nm_ip4_config_subtract (priv->ext_ip4_config, priv->dev_ip4_config, - default_route_metric_penalty_get (self, AF_INET)); + if (applied_config_get_current (&priv->dev_ip4_config)) { + nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip4_config, + applied_config_get_current (&priv->dev_ip4_config), + default_route_metric_penalty_get (self, AF_INET)); } - if (priv->wwan_ip4_config) { - nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config, - default_route_metric_penalty_get (self, AF_INET)); + if (applied_config_get_current (&priv->wwan_ip4_config)) { + nm_ip_config_subtract ((NMIPConfig *) priv->ext_ip4_config, + applied_config_get_current (&priv->wwan_ip4_config), + default_route_metric_penalty_get (self, AF_INET)); } for (iter = priv->vpn4_configs; iter; iter = iter->next) nm_ip4_config_subtract (priv->ext_ip4_config, iter->data, 0); @@ -12429,9 +12474,9 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type) nm_device_set_ip6_config (self, NULL, TRUE); g_clear_object (&priv->proxy_config); g_clear_object (&priv->con_ip4_config); - g_clear_object (&priv->dev_ip4_config); + applied_config_clear (&priv->dev_ip4_config); + applied_config_clear (&priv->wwan_ip4_config); g_clear_object (&priv->ext_ip4_config); - g_clear_object (&priv->wwan_ip4_config); g_clear_object (&priv->ip4_config); g_clear_object (&priv->con_ip6_config); g_clear_object (&priv->ac_ip6_config); |