From ca0f147bf45e291914b4ec3c6afbc812dd8010b1 Mon Sep 17 00:00:00 2001 From: Beniamino Galvani Date: Sat, 21 Jul 2018 10:42:04 +0200 Subject: [PATCH] core: handle route metric when reapplying dynamic IP methods For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is set at activation/renewal time using the value from static configuration. To support runtime change we need to update the dynamic configuration in place and tell the DHCP client the new value to use for future renewals. https://bugzilla.redhat.com/show_bug.cgi?id=1528071 (cherry picked from commit b9e6433a024c13631c984797c964f1863de83113) --- src/devices/nm-device.c | 65 +++++++++++++++++++++++++++++++++++++---- src/nm-ip4-config.c | 31 ++++++++++++++++++++ src/nm-ip4-config.h | 1 + src/nm-ip6-config.c | 31 ++++++++++++++++++++ src/nm-ip6-config.h | 2 ++ 5 files changed, 124 insertions(+), 6 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 52ed227179..a7597f4f0a 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -10340,10 +10340,37 @@ nm_device_reactivate_ip4_config (NMDevice *self, _set_ip_state (self, AF_INET, IP_WAIT); if (!nm_device_activate_stage3_ip4_start (self)) _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration"); - } else { - if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) - _LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration"); + return; } + + if (s_ip4_old && s_ip4_new) { + gint64 metric_old, metric_new; + + /* For dynamic IP methods (DHCP, IPv4LL, WWAN) the route metric is + * set at activation/renewal time using the value from static + * configuration. To support runtime change we need to update the + * dynamic configuration in place and tell the DHCP client the new + * value to use for future renewals. + */ + metric_old = nm_setting_ip_config_get_route_metric (s_ip4_old); + metric_new = nm_setting_ip_config_get_route_metric (s_ip4_new); + + if (metric_old != metric_new) { + if (priv->dev_ip4_config.orig) { + nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->dev_ip4_config.orig, + nm_device_get_route_metric (self, AF_INET)); + } + if (priv->wwan_ip_config_4.orig) { + nm_ip4_config_update_routes_metric ((NMIP4Config *) priv->wwan_ip_config_4.orig, + nm_device_get_route_metric (self, AF_INET)); + } + if (priv->dhcp4.client) + nm_dhcp_client_set_route_metric (priv->dhcp4.client, metric_new); + } + } + + if (!ip_config_merge_and_apply (self, AF_INET, TRUE)) + _LOGW (LOGD_IP4, "Failed to reapply IPv4 configuration"); } } @@ -10385,10 +10412,36 @@ nm_device_reactivate_ip6_config (NMDevice *self, _set_ip_state (self, AF_INET6, IP_WAIT); if (!nm_device_activate_stage3_ip6_start (self)) _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration"); - } else { - if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) - _LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration"); + return; } + + if (s_ip6_old && s_ip6_new) { + gint64 metric_old, metric_new; + + /* See comment in nm_device_reactivate_ip6_config() */ + metric_old = nm_setting_ip_config_get_route_metric (s_ip6_old); + metric_new = nm_setting_ip_config_get_route_metric (s_ip6_new); + + if (metric_old != metric_new) { + if (priv->ac_ip6_config.orig) { + nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->ac_ip6_config.orig, + nm_device_get_route_metric (self, AF_INET6)); + } + if (priv->dhcp6.ip6_config.orig) { + nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->dhcp6.ip6_config.orig, + nm_device_get_route_metric (self, AF_INET6)); + } + if (priv->wwan_ip_config_6.orig) { + nm_ip6_config_update_routes_metric ((NMIP6Config *) priv->wwan_ip_config_6.orig, + nm_device_get_route_metric (self, AF_INET6)); + } + if (priv->dhcp6.client) + nm_dhcp_client_set_route_metric (priv->dhcp6.client, metric_new); + } + } + + if (!ip_config_merge_and_apply (self, AF_INET6, TRUE)) + _LOGW (LOGD_IP4, "Failed to reapply IPv6 configuration"); } } diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 6ae81b5730..657ebfc0b2 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -645,6 +645,37 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i return self; } +void +nm_ip4_config_update_routes_metric (NMIP4Config *self, gint64 metric) +{ + gs_free NMPlatformIP4Route *routes = NULL; + gboolean need_update = FALSE; + const NMPlatformIP4Route *r; + NMDedupMultiIter iter; + guint num = 0, i = 0; + + nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { + if (r->metric != metric) + need_update = TRUE; + num++; + } + if (!need_update) + return; + + routes = g_new (NMPlatformIP4Route, num); + nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { + routes[i] = *r; + routes[i].metric = metric; + i++; + } + + g_object_freeze_notify (G_OBJECT (self)); + nm_ip4_config_reset_routes (self); + for (i = 0; i < num; i++) + nm_ip4_config_add_route (self, &routes[i], NULL); + g_object_thaw_notify (G_OBJECT (self)); +} + void nm_ip4_config_add_dependent_routes (NMIP4Config *self, guint32 route_table, diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 78aca14e43..45c1fa3faa 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -223,6 +223,7 @@ const NMPlatformIP4Route *_nmtst_ip4_config_get_route (const NMIP4Config *self, const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, in_addr_t host, guint32 route_table); +void nm_ip4_config_update_routes_metric (NMIP4Config *self, gint64 metric); void nm_ip4_config_reset_nameservers (NMIP4Config *self); void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 nameserver); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 9807d3882c..3869fee81b 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -427,6 +427,37 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i return self; } +void +nm_ip6_config_update_routes_metric (NMIP6Config *self, gint64 metric) +{ + gs_free NMPlatformIP6Route *routes = NULL; + gboolean need_update = FALSE; + const NMPlatformIP6Route *r; + NMDedupMultiIter iter; + guint num = 0, i = 0; + + nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { + if (r->metric != metric) + need_update = TRUE; + num++; + } + if (!need_update) + return; + + routes = g_new (NMPlatformIP6Route, num); + nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { + routes[i] = *r; + routes[i].metric = metric; + i++; + } + + g_object_freeze_notify (G_OBJECT (self)); + nm_ip6_config_reset_routes (self); + for (i = 0; i < num; i++) + nm_ip6_config_add_route (self, &routes[i], NULL); + g_object_thaw_notify (G_OBJECT (self)); +} + void nm_ip6_config_add_dependent_routes (NMIP6Config *self, guint32 route_table, diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 9762ef48be..b8e80410ab 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -224,4 +224,6 @@ void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self, guint32 route_metric, gboolean kernel_support_rta_pref); +void nm_ip6_config_update_routes_metric (NMIP6Config *self, gint64 metric); + #endif /* __NETWORKMANAGER_IP6_CONFIG_H__ */