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__ */