From bdf4ea8aa5e7989a2b041d5a11eae625c7200d72 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 12 Mar 2015 07:02:48 +0100 Subject: [PATCH 01/12] trivial: move nm_device_queued_ip_config_change_clear() Just move it upwards, we'll need it in nm_device_activate_schedule_ip4_config_result(). (cherry picked from commit a772fde00d50e134500942aaf039cd4fa28951da) --- src/devices/nm-device.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ea255b7cbb..31f2c5b2d0 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5527,6 +5527,18 @@ out: return FALSE; } +static void +nm_device_queued_ip_config_change_clear (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->queued_ip_config_id) { + _LOGD (LOGD_DEVICE, "clearing queued IP config change"); + g_source_remove (priv->queued_ip_config_id); + priv->queued_ip_config_id = 0; + } +} + void nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *config) { @@ -6998,18 +7010,6 @@ device_ip_changed (NMPlatform *platform, } } -static void -nm_device_queued_ip_config_change_clear (NMDevice *self) -{ - NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - - if (priv->queued_ip_config_id) { - _LOGD (LOGD_DEVICE, "clearing queued IP config change"); - g_source_remove (priv->queued_ip_config_id); - priv->queued_ip_config_id = 0; - } -} - /** * nm_device_get_managed(): * @self: the #NMDevice From 8f01cad71c1fb333603777cdefd361cb25084d08 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 21 Nov 2014 18:56:32 +0100 Subject: [PATCH 02/12] device: refactor ipx_config_merge_and_apply() No functional change, but restructure code to make it clearer(?). (cherry picked from commit 4a83afd530fd5e466be3ac653ac632c9c0157614) --- src/devices/nm-device.c | 235 ++++++++++++++++++++++------------------ 1 file changed, 130 insertions(+), 105 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 31f2c5b2d0..ad1c7dd851 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3130,6 +3130,7 @@ ip4_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; NMIP4Config *composite; + gboolean has_direct_route; const guint32 default_route_metric = nm_device_get_ip4_route_metric (self); /* Merge all the configs into the composite config */ @@ -3157,70 +3158,81 @@ ip4_config_merge_and_apply (NMDevice *self, * be redundant, so don't bother. */ 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. + * + * We keep track of the default route of a device in a private field. + * NMDevice needs to know the default route at this point, because the gateway + * might require a direct route (see below). + * + * But also, we don't want to add the default route to priv->ip4_config, + * because the default route from the setting might not be the same that + * NMDefaultRouteManager eventually configures (because the it might + * tweak the effective metric). + */ + + /* unless we come to a different conclusion below, we have no default route and + * the route is assumed. */ priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; - if (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP4Route *route = &priv->default_route.v4; - if (!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); + if (!connection) + goto END_ADD_DEFAULT_ROUTE; + + if ( !nm_device_uses_assumed_connection (self) + && nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { + guint32 gateway; + + priv->default_route.v4_is_assumed = FALSE; + + if ( !(!commit && priv->ext_ip4_config_had_any_addresses) + && !( commit && nm_ip4_config_get_num_addresses (composite))) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; } - /* Add the default route. - * - * We keep track of the default route of a device in a private field. - * NMDevice needs to know the default route at this point, because the gateway - * might require a direct route (see below). - * - * But also, we don't want to add the default route to priv->ip4_config, - * because the default route from the setting might not be the same that - * NMDefaultRouteManager eventually configures (because the it might - * tweak the effective metric). - */ - if ( !assumed - && nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { - guint32 gateway = 0; + gateway = nm_ip4_config_get_gateway (composite); + if ( !gateway + && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) + goto END_ADD_DEFAULT_ROUTE; - priv->default_route.v4_is_assumed = FALSE; - if ( (!commit && priv->ext_ip4_config_had_any_addresses) - || ( commit && nm_ip4_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip4_config_get_gateway (composite); - if ( gateway - || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = gateway; - route->metric = default_route_metric; - route->mss = nm_ip4_config_get_mss (composite); - priv->default_route.v4_has = TRUE; + has_direct_route = ( gateway == 0 + || nm_ip4_config_get_subnet_for_host (composite, gateway) + || nm_ip4_config_get_direct_route_for_host (composite, gateway)); - if ( gateway - && !nm_ip4_config_get_subnet_for_host (composite, gateway) - && !nm_ip4_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP4Route r = *route; + /* In the (!has_direct_route && !commit) case it is not clear whether + * adding the default route will succeed. Still give it a try and add it */ - r.network = gateway; - r.plen = 32; - r.gateway = 0; - nm_ip4_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) route); + priv->default_route.v4_has = TRUE; + memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4)); + priv->default_route.v4.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v4.gateway = gateway; + priv->default_route.v4.metric = default_route_metric; + priv->default_route.v4.mss = nm_ip4_config_get_mss (composite); + + if (!has_direct_route && commit) { + NMPlatformIP4Route r = priv->default_route.v4; + + /* add a direct route to the gateway */ + r.network = gateway; + r.plen = 32; + r.gateway = 0; + nm_ip4_config_add_route (composite, &r); } + } else { + /* For interfaces that are assumed and that have no default-route by configuration, we assume + * the default connection and pick up whatever is configured. */ + priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); } +END_ADD_DEFAULT_ROUTE: + /* Allow setting MTU etc */ if (commit) { if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) @@ -3694,6 +3706,7 @@ ip6_config_merge_and_apply (NMDevice *self, NMConnection *connection; gboolean success; NMIP6Config *composite; + gboolean has_direct_route; /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); @@ -3720,69 +3733,81 @@ ip6_config_merge_and_apply (NMDevice *self, * be redundant, so don't bother. */ 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. + * + * We keep track of the default route of a device in a private field. + * NMDevice needs to know the default route at this point, because the gateway + * might require a direct route (see below). + * + * But also, we don't want to add the default route to priv->ip6_config, + * because the default route from the setting might not be the same that + * NMDefaultRouteManager eventually configures (because the it might + * tweak the effective metric). + */ + + /* unless we come to a different conclusion below, we have no default route and + * the route is assumed. */ priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; - if (connection) { - gboolean assumed = nm_device_uses_assumed_connection (self); - NMPlatformIP6Route *route = &priv->default_route.v6; - if (!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)); + if (!connection) + goto END_ADD_DEFAULT_ROUTE; + + if ( !nm_device_uses_assumed_connection (self) + && nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { + const struct in6_addr *gateway; + + priv->default_route.v6_is_assumed = FALSE; + + if ( !(!commit && priv->ext_ip6_config_had_any_addresses) + && !( commit && nm_ip6_config_get_num_addresses (composite))) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; } - /* Add the default route. - * - * We keep track of the default route of a device in a private field. - * NMDevice needs to know the default route at this point, because the gateway - * might require a direct route (see below). - * - * But also, we don't want to add the default route to priv->ip4_config, - * because the default route from the setting might not be the same that - * NMDefaultRouteManager eventually configures (because the it might - * tweak the effective metric). - */ - if ( !assumed - && nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { - const struct in6_addr *gateway = NULL; + gateway = nm_ip6_config_get_gateway (composite); + if (!gateway) + goto END_ADD_DEFAULT_ROUTE; - priv->default_route.v6_is_assumed = FALSE; - if ( (!commit && priv->ext_ip6_config_had_any_addresses) - || ( commit && nm_ip6_config_get_num_addresses (composite))) { - /* For managed interfaces, we can only configure a gateway, if either the external config indicates - * that we already have addresses, or if we are about to commit any addresses. - * Otherwise adding a default route will fail, because NMDefaultRouteManager does not add any - * addresses for the route. */ - gateway = nm_ip6_config_get_gateway (composite); - if (gateway) { - memset (route, 0, sizeof (*route)); - route->source = NM_IP_CONFIG_SOURCE_USER; - route->gateway = *gateway; - route->metric = nm_device_get_ip6_route_metric (self); - route->mss = nm_ip6_config_get_mss (composite); - priv->default_route.v6_has = TRUE; - if ( gateway - && !nm_ip6_config_get_subnet_for_host (composite, gateway) - && !nm_ip6_config_get_direct_route_for_host (composite, gateway)) { - /* add a direct route to the gateway */ - NMPlatformIP6Route r = *route; + has_direct_route = ( nm_ip6_config_get_subnet_for_host (composite, gateway) + || nm_ip6_config_get_direct_route_for_host (composite, gateway)); - r.network = *gateway; - r.plen = 128; - r.gateway = in6addr_any; - nm_ip6_config_add_route (composite, &r); - } - } - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) route); + + /* In the (!has_direct_route && !commit) case it is not clear whether + * adding the default route will succeed. Still give it a try and add it */ + + priv->default_route.v6_has = TRUE; + memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6)); + priv->default_route.v6.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v6.gateway = *gateway; + priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self); + priv->default_route.v6.mss = nm_ip6_config_get_mss (composite); + + if (!has_direct_route && commit) { + NMPlatformIP6Route r = priv->default_route.v6; + + /* add a direct route to the gateway */ + r.network = *gateway; + r.plen = 128; + r.gateway = in6addr_any; + nm_ip6_config_add_route (composite, &r); } + } else { + /* For interfaces that are assumed and that have no default-route by configuration, we assume + * the default connection and pick up whatever is configured. */ + priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); } +END_ADD_DEFAULT_ROUTE: + nm_ip6_config_addresses_sort (composite, priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); From fd80e62f47fc9e7ffbba2034d05f6166c33d8587 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 20 Nov 2014 23:36:50 +0100 Subject: [PATCH 03/12] core: refactor subtract() functions in NMIP?Config Factor out code of the nm_ip4_config_subtract() and nm_ip6_config_subtract() functions. The code can be reused in the following commit. (cherry picked from commit 92d800b2e35b4c36c13dfb088f1d7a69b83f7191) --- src/nm-ip4-config.c | 206 ++++++++++++++++++++++++++++---------------- src/nm-ip6-config.c | 147 ++++++++++++++++++++----------- 2 files changed, 230 insertions(+), 123 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 8dee29e81c..07e65724af 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -536,6 +536,117 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) g_object_thaw_notify (G_OBJECT (dst)); } +/*******************************************************************************/ + +static int +_addresses_get_index (const NMIP4Config *self, const NMPlatformIP4Address *addr) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP4Address *a = &g_array_index (priv->addresses, NMPlatformIP4Address, i); + + if (addr->address == a->address && + addr->plen == a->plen) + return (int) i; + } + return -1; +} + +static int +_nameservers_get_index (const NMIP4Config *self, guint32 ns) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nameservers->len; i++) { + guint32 n = g_array_index (priv->nameservers, guint32, i); + + if (ns == n) + return (int) i; + } + return -1; +} + +static int +_routes_get_index (const NMIP4Config *self, const NMPlatformIP4Route *route) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP4Route *r = &g_array_index (priv->routes, NMPlatformIP4Route, i); + + if ( route->network == r->network + && route->plen == r->plen) + return (int) i; + } + return -1; +} + +static int +_domains_get_index (const NMIP4Config *self, const char *domain) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->domains->len; i++) { + const char *d = g_ptr_array_index (priv->domains, i); + + if (g_strcmp0 (domain, d) == 0) + return (int) i; + } + return -1; +} + +static int +_searches_get_index (const NMIP4Config *self, const char *search) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->searches->len; i++) { + const char *s = g_ptr_array_index (priv->searches, i); + + if (g_strcmp0 (search, s) == 0) + return (int) i; + } + return -1; +} + +static int +_nis_servers_get_index (const NMIP4Config *self, guint32 nis_server) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nis->len; i++) { + guint32 n = g_array_index (priv->nis, guint32, i); + + if (n == nis_server) + return (int) i; + } + return -1; +} + +static int +_wins_get_index (const NMIP4Config *self, guint32 wins_server) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->wins->len; i++) { + guint32 n = g_array_index (priv->wins, guint32, i); + + if (n == wins_server) + return (int) i; + } + return -1; +} + +/*******************************************************************************/ + /** * nm_ip4_config_subtract: * @dst: config from which to remove everything in @src @@ -546,7 +657,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src) void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) { - guint32 i, j; + guint32 i; + gint idx; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -555,31 +667,16 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* addresses */ for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) { - const NMPlatformIP4Address *src_addr = nm_ip4_config_get_address (src, i); - - for (j = 0; j < nm_ip4_config_get_num_addresses (dst); j++) { - const NMPlatformIP4Address *dst_addr = nm_ip4_config_get_address (dst, j); - - if (src_addr->address == dst_addr->address && - src_addr->plen == dst_addr->plen) { - nm_ip4_config_del_address (dst, j); - break; - } - } + idx = _addresses_get_index (dst, nm_ip4_config_get_address (src, i)); + if (idx >= 0) + nm_ip4_config_del_address (dst, idx); } /* nameservers */ for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) { - guint32 src_ns = nm_ip4_config_get_nameserver (src, i); - - for (j = 0; j < nm_ip4_config_get_num_nameservers (dst); j++) { - guint32 dst_ns = nm_ip4_config_get_nameserver (dst, j); - - if (dst_ns == src_ns) { - nm_ip4_config_del_nameserver (dst, j); - break; - } - } + idx = _nameservers_get_index (dst, nm_ip4_config_get_nameserver (src, i)); + if (idx >= 0) + nm_ip4_config_del_nameserver (dst, idx); } /* default gateway */ @@ -591,44 +688,23 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* routes */ for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) { - const NMPlatformIP4Route *src_route = nm_ip4_config_get_route (src, i); - - for (j = 0; j < nm_ip4_config_get_num_routes (dst); j++) { - const NMPlatformIP4Route *dst_route = nm_ip4_config_get_route (dst, j); - - if (src_route->network == dst_route->network && src_route->plen == dst_route->plen) { - nm_ip4_config_del_route (dst, j); - break; - } - } + idx = _routes_get_index (dst, nm_ip4_config_get_route (src, i)); + if (idx >= 0) + nm_ip4_config_del_route (dst, idx); } /* domains */ for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) { - const char *src_domain = nm_ip4_config_get_domain (src, i); - - for (j = 0; j < nm_ip4_config_get_num_domains (dst); j++) { - const char *dst_domain = nm_ip4_config_get_domain (dst, j); - - if (g_strcmp0 (src_domain, dst_domain) == 0) { - nm_ip4_config_del_domain (dst, j); - break; - } - } + idx = _domains_get_index (dst, nm_ip4_config_get_domain (src, i)); + if (idx >= 0) + nm_ip4_config_del_domain (dst, idx); } /* dns searches */ for (i = 0; i < nm_ip4_config_get_num_searches (src); i++) { - const char *src_search = nm_ip4_config_get_search (src, i); - - for (j = 0; j < nm_ip4_config_get_num_searches (dst); j++) { - const char *dst_search = nm_ip4_config_get_search (dst, j); - - if (g_strcmp0 (src_search, dst_search) == 0) { - nm_ip4_config_del_search (dst, j); - break; - } - } + idx = _searches_get_index (dst, nm_ip4_config_get_search (src, i)); + if (idx >= 0) + nm_ip4_config_del_search (dst, idx); } /* MSS */ @@ -641,16 +717,9 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* NIS */ for (i = 0; i < nm_ip4_config_get_num_nis_servers (src); i++) { - guint32 src_nis = nm_ip4_config_get_nis_server (src, i); - - for (j = 0; j < nm_ip4_config_get_num_nis_servers (dst); j++) { - guint32 dst_nis = nm_ip4_config_get_nis_server (dst, j); - - if (dst_nis == src_nis) { - nm_ip4_config_del_nis_server (dst, j); - break; - } - } + idx = _nis_servers_get_index (dst, nm_ip4_config_get_nis_server (src, i)); + if (idx >= 0) + nm_ip4_config_del_nis_server (dst, idx); } if (g_strcmp0 (nm_ip4_config_get_nis_domain (src), nm_ip4_config_get_nis_domain (dst)) == 0) @@ -658,16 +727,9 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* WINS */ for (i = 0; i < nm_ip4_config_get_num_wins (src); i++) { - guint32 src_wins = nm_ip4_config_get_wins (src, i); - - for (j = 0; j < nm_ip4_config_get_num_wins (dst); j++) { - guint32 dst_wins = nm_ip4_config_get_wins (dst, j); - - if (dst_wins == src_wins) { - nm_ip4_config_del_wins (dst, j); - break; - } - } + idx = _wins_get_index (dst, nm_ip4_config_get_wins (src, i)); + if (idx >= 0) + nm_ip4_config_del_wins (dst, idx); } g_object_thaw_notify (G_OBJECT (dst)); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 40fdcb1999..cf8cdb1cc0 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -653,6 +653,85 @@ nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6 return FALSE; } +/*******************************************************************************/ + +static int +_addresses_get_index (const NMIP6Config *self, const NMPlatformIP6Address *addr) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->addresses->len; i++) { + const NMPlatformIP6Address *a = &g_array_index (priv->addresses, NMPlatformIP6Address, i); + + if (IN6_ARE_ADDR_EQUAL (&addr->address, &a->address)) + return (int) i; + } + return -1; +} + +static int +_nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->nameservers->len; i++) { + const struct in6_addr *n = &g_array_index (priv->nameservers, struct in6_addr, i); + + if (IN6_ARE_ADDR_EQUAL (ns, n)) + return (int) i; + } + return -1; +} + +static int +_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->routes->len; i++) { + const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i); + + if (routes_are_duplicate (route, r, FALSE)) + return (int) i; + } + return -1; +} + +static int +_domains_get_index (const NMIP6Config *self, const char *domain) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->domains->len; i++) { + const char *d = g_ptr_array_index (priv->domains, i); + + if (g_strcmp0 (domain, d) == 0) + return (int) i; + } + return -1; +} + +static int +_searches_get_index (const NMIP6Config *self, const char *search) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + guint i; + + for (i = 0; i < priv->searches->len; i++) { + const char *s = g_ptr_array_index (priv->searches, i); + + if (g_strcmp0 (search, s) == 0) + return (int) i; + } + return -1; +} + +/*******************************************************************************/ + /** * nm_ip6_config_subtract: * @dst: config from which to remove everything in @src @@ -663,7 +742,8 @@ nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6 void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) { - guint32 i, j; + guint i; + gint idx; const struct in6_addr *dst_tmp, *src_tmp; g_return_if_fail (src != NULL); @@ -673,30 +753,16 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* addresses */ for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) { - const NMPlatformIP6Address *src_addr = nm_ip6_config_get_address (src, i); - - for (j = 0; j < nm_ip6_config_get_num_addresses (dst); j++) { - const NMPlatformIP6Address *dst_addr = nm_ip6_config_get_address (dst, j); - - if (IN6_ARE_ADDR_EQUAL (&src_addr->address, &dst_addr->address)) { - nm_ip6_config_del_address (dst, j); - break; - } - } + idx = _addresses_get_index (dst, nm_ip6_config_get_address (src, i)); + if (idx >= 0) + nm_ip6_config_del_address (dst, idx); } /* nameservers */ for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) { - const struct in6_addr *src_ns = nm_ip6_config_get_nameserver (src, i); - - for (j = 0; j < nm_ip6_config_get_num_nameservers (dst); j++) { - const struct in6_addr *dst_ns = nm_ip6_config_get_nameserver (dst, j); - - if (IN6_ARE_ADDR_EQUAL (src_ns, dst_ns)) { - nm_ip6_config_del_nameserver (dst, j); - break; - } - } + idx = _nameservers_get_index (dst, nm_ip6_config_get_nameserver (src, i)); + if (idx >= 0) + nm_ip6_config_del_nameserver (dst, idx); } /* default gateway */ @@ -710,44 +776,23 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* routes */ for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) { - const NMPlatformIP6Route *src_route = nm_ip6_config_get_route (src, i); - - for (j = 0; j < nm_ip6_config_get_num_routes (dst); j++) { - const NMPlatformIP6Route *dst_route = nm_ip6_config_get_route (dst, j); - - if (routes_are_duplicate (src_route, dst_route, FALSE)) { - nm_ip6_config_del_route (dst, j); - break; - } - } + idx = _routes_get_index (dst, nm_ip6_config_get_route (src, i)); + if (idx >= 0) + nm_ip6_config_del_route (dst, idx); } /* domains */ for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) { - const char *src_domain = nm_ip6_config_get_domain (src, i); - - for (j = 0; j < nm_ip6_config_get_num_domains (dst); j++) { - const char *dst_domain = nm_ip6_config_get_domain (dst, j); - - if (g_strcmp0 (src_domain, dst_domain) == 0) { - nm_ip6_config_del_domain (dst, j); - break; - } - } + idx = _domains_get_index (dst, nm_ip6_config_get_domain (src, i)); + if (idx >= 0) + nm_ip6_config_del_domain (dst, idx); } /* dns searches */ for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { - const char *src_search = nm_ip6_config_get_search (src, i); - - for (j = 0; j < nm_ip6_config_get_num_searches (dst); j++) { - const char *dst_search = nm_ip6_config_get_search (dst, j); - - if (g_strcmp0 (src_search, dst_search) == 0) { - nm_ip6_config_del_search (dst, j); - break; - } - } + idx = _searches_get_index (dst, nm_ip6_config_get_search (src, i)); + if (idx >= 0) + nm_ip6_config_del_search (dst, idx); } if (nm_ip6_config_get_mss (src) == nm_ip6_config_get_mss (dst)) From 4001615034a130a946db17374a8634453118de2f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 20 Nov 2014 23:39:21 +0100 Subject: [PATCH 04/12] core: add intersect() functions to NMIP?Config (cherry picked from commit 49d700e862cd16ab398439790ebe889856f1e6cb) --- src/nm-ip4-config.c | 82 +++++++++++++++++++++++++++++++++++++++++++++ src/nm-ip4-config.h | 1 + src/nm-ip6-config.c | 70 ++++++++++++++++++++++++++++++++++++++ src/nm-ip6-config.h | 1 + 4 files changed, 154 insertions(+) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 07e65724af..b15fc229dc 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -735,6 +735,88 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) g_object_thaw_notify (G_OBJECT (dst)); } +void +nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) +{ + guint32 i; + gint idx; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip4_config_get_num_addresses (dst); ) { + idx = _addresses_get_index (src, nm_ip4_config_get_address (dst, i)); + if (idx < 0) + nm_ip4_config_del_address (dst, i); + else + i++; + } + + /* nameservers */ + for (i = 0; i < nm_ip4_config_get_num_nameservers (dst); ) { + idx = _nameservers_get_index (src, nm_ip4_config_get_nameserver (dst, i)); + if (idx < 0) + nm_ip4_config_del_nameserver (dst, i); + else + i++; + } + + /* default gateway */ + if ( !nm_ip4_config_get_num_addresses (dst) + || (nm_ip4_config_get_gateway (src) != nm_ip4_config_get_gateway (dst))) + nm_ip4_config_set_gateway (dst, 0); + + /* routes */ + for (i = 0; i < nm_ip4_config_get_num_routes (dst); ) { + idx = _routes_get_index (src, nm_ip4_config_get_route (dst, i)); + if (idx < 0) + nm_ip4_config_del_route (dst, i); + else + i++; + } + + /* domains */ + for (i = 0; i < nm_ip4_config_get_num_domains (dst); ) { + idx = _domains_get_index (src, nm_ip4_config_get_domain (dst, i)); + if (idx < 0) + nm_ip4_config_del_domain (dst, i); + else + i++; + } + + /* dns searches */ + for (i = 0; i < nm_ip4_config_get_num_searches (dst); ) { + idx = _searches_get_index (src, nm_ip4_config_get_search (dst, i)); + if (idx < 0) + nm_ip4_config_del_search (dst, i); + else + i++; + } + + /* NIS */ + for (i = 0; i < nm_ip4_config_get_num_nis_servers (dst); ) { + idx = _nis_servers_get_index (src, nm_ip4_config_get_nis_server (dst, i)); + if (idx < 0) + nm_ip4_config_del_nis_server (dst, i); + else + i++; + } + + /* WINS */ + for (i = 0; i < nm_ip4_config_get_num_wins (dst); ) { + idx = _wins_get_index (src, nm_ip4_config_get_wins (dst, i)); + if (idx < 0) + nm_ip4_config_del_wins (dst, i); + else + i++; + } + + g_object_thaw_notify (G_OBJECT (dst)); +} + /** * nm_ip4_config_replace: diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 5ac455d84f..2b3b24e6af 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -71,6 +71,7 @@ NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config); /* Utility functions */ void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src); void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src); +void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 dest, int plen); void nm_ip4_config_dump (const NMIP4Config *config, const char *detail); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index cf8cdb1cc0..82c74eb1ec 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -801,6 +801,76 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) g_object_thaw_notify (G_OBJECT (dst)); } +void +nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) +{ + guint i; + gint idx; + const struct in6_addr *dst_tmp, *src_tmp; + + g_return_if_fail (src != NULL); + g_return_if_fail (dst != NULL); + + g_object_freeze_notify (G_OBJECT (dst)); + + /* addresses */ + for (i = 0; i < nm_ip6_config_get_num_addresses (dst); ) { + idx = _addresses_get_index (src, nm_ip6_config_get_address (dst, i)); + if (idx < 0) + nm_ip6_config_del_address (dst, i); + else + i++; + } + + /* nameservers */ + for (i = 0; i < nm_ip6_config_get_num_nameservers (dst); ) { + idx = _nameservers_get_index (src, nm_ip6_config_get_nameserver (dst, i)); + if (idx < 0) + nm_ip6_config_del_nameserver (dst, i); + else + i++; + } + + /* default gateway */ + dst_tmp = nm_ip6_config_get_gateway (dst); + if (dst_tmp) { + src_tmp = nm_ip6_config_get_gateway (src); + if ( !nm_ip6_config_get_num_addresses (dst) + || !src_tmp + || !IN6_ARE_ADDR_EQUAL (src_tmp, dst_tmp)) + nm_ip6_config_set_gateway (dst, NULL); + } + + /* routes */ + for (i = 0; i < nm_ip6_config_get_num_routes (dst); ) { + idx = _routes_get_index (src, nm_ip6_config_get_route (dst, i)); + if (idx < 0) + nm_ip6_config_del_route (dst, i); + else + i++; + } + + /* domains */ + for (i = 0; i < nm_ip6_config_get_num_domains (src); ) { + idx = _domains_get_index (src, nm_ip6_config_get_domain (dst, i)); + if (idx < 0) + nm_ip6_config_del_domain (dst, i); + else + i++; + } + + /* dns searches */ + for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { + idx = _searches_get_index (src, nm_ip6_config_get_search (dst, i)); + if (idx < 0) + nm_ip6_config_del_search (dst, i); + else + i++; + } + + g_object_thaw_notify (G_OBJECT (dst)); +} + /** * nm_ip6_config_replace: * @dst: config which will be replaced with everything in @src diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index f1d2dc8dd9..04c9e00341 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -71,6 +71,7 @@ NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); /* Utility functions */ void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src); void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src); +void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); int nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *dest, int plen); void nm_ip6_config_dump (const NMIP6Config *config, const char *detail); From f6da80f153c1049934bec580881fd82143eb5546 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 20 Jan 2015 14:19:08 +0100 Subject: [PATCH 05/12] device: require a direct route for IPv6 gateway In the IPv4 case, we check whether we have a direct route to the gateway also by looking at the configured addresses/subnets. That is correct, because every IPv4 address also implies a subnet route. For IPv6, we explicitly add all subnet routes manually (noprefixroute), hence, we have a direct route exactly if we have it in our list. Regardless of the configured IPv6 prefixes. (cherry picked from commit 2c0644908524b6d9256d377b28194ba3d10535d5) --- src/devices/nm-device.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index ad1c7dd851..fdf45091b8 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3777,8 +3777,8 @@ ip6_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; - has_direct_route = ( nm_ip6_config_get_subnet_for_host (composite, gateway) - || nm_ip6_config_get_direct_route_for_host (composite, gateway)); + has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL; + /* In the (!has_direct_route && !commit) case it is not clear whether From ab6548c62134518ba2871306397e7fb9c84260ca Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 21 Nov 2014 13:13:48 +0100 Subject: [PATCH 06/12] 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 (cherry picked from commit 557667df12fc05b76326d6406553985effeeb2ac) --- src/devices/nm-device.c | 134 ++++++++++++++++++++++++++++++---------- 1 file changed, 100 insertions(+), 34 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index fdf45091b8..19a1bdd760 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -250,9 +250,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; @@ -287,10 +287,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 */ guint32 ip6_mtu; @@ -3091,6 +3091,43 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat return success; } +/*********************************************/ + +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 */ @@ -3140,6 +3177,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) @@ -3153,17 +3193,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. * @@ -3191,8 +3226,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; } @@ -3710,7 +3744,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) @@ -3728,17 +3763,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. * @@ -3766,8 +3796,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; } @@ -6936,13 +6965,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) @@ -6956,14 +7003,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) @@ -7556,20 +7623,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 */ From 43b77d7c3275b841988be87e42e57b10daafb29d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 21 Nov 2014 20:21:37 +0100 Subject: [PATCH 07/12] device: always pickup externally configured default routes for a device Even more eagerly pickup external default routes from the device. For assumed devices we already picked up the default route. (a) For assumed devices we already did not enforce the default route at all. Instead it was always picked up by from the actualy system configuration. Note that this is the case for assumed-generated connections and for assuming existing connections. That means that when NM assumes a connection at startup, it will never actively manage the default route on that interface. It will only react on what is present. (b) For managed devices that have by configuration no default route, still pick up the default route. That means, that even a device that is managed and never-default=yes, can have the default route -- if configured externally. (c) Only during a commit phase (i.e. when we have new configuraiton to be applied), we enforce the default route or its absence. (d) During any IP change event from platform, we again pickup whatever is present. That means if you remove the default route from a managed interface, NM will not re-add it until anything triggers (c). This also means, that during the commit phase, we add default routes as 'synced' to the default-route-manager, but the following event from platform, will change the route entry immediately to 'non-synced'. That is expected and correct. (cherry picked from commit da708059dabb2854d11eed1a403398327b31535b) --- src/devices/nm-device.c | 160 ++++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 70 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 19a1bdd760..d928389554 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3169,6 +3169,7 @@ ip4_config_merge_and_apply (NMDevice *self, NMIP4Config *composite; gboolean has_direct_route; const guint32 default_route_metric = nm_device_get_ip4_route_metric (self); + guint32 gateway; /* Merge all the configs into the composite config */ if (config) { @@ -3217,56 +3218,65 @@ ip4_config_merge_and_apply (NMDevice *self, priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; - if (!connection) + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + if (nm_device_uses_assumed_connection (self)) goto END_ADD_DEFAULT_ROUTE; - if ( !nm_device_uses_assumed_connection (self) - && nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { - guint32 gateway; - priv->default_route.v4_is_assumed = FALSE; + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v4_is_assumed = FALSE; - if (!nm_ip4_config_get_num_addresses (composite)) { - /* without addresses we can have no default route. */ - goto END_ADD_DEFAULT_ROUTE; - } + if ( !connection + || !nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) + goto END_ADD_DEFAULT_ROUTE; - gateway = nm_ip4_config_get_gateway (composite); - if ( !gateway - && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) - goto END_ADD_DEFAULT_ROUTE; + if (!nm_ip4_config_get_num_addresses (composite)) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; + } - has_direct_route = ( gateway == 0 - || nm_ip4_config_get_subnet_for_host (composite, gateway) - || nm_ip4_config_get_direct_route_for_host (composite, gateway)); + gateway = nm_ip4_config_get_gateway (composite); + if ( !gateway + && nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM) + goto END_ADD_DEFAULT_ROUTE; - /* In the (!has_direct_route && !commit) case it is not clear whether - * adding the default route will succeed. Still give it a try and add it */ + has_direct_route = ( gateway == 0 + || nm_ip4_config_get_subnet_for_host (composite, gateway) + || nm_ip4_config_get_direct_route_for_host (composite, gateway)); - priv->default_route.v4_has = TRUE; - memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4)); - priv->default_route.v4.source = NM_IP_CONFIG_SOURCE_USER; - priv->default_route.v4.gateway = gateway; - priv->default_route.v4.metric = default_route_metric; - priv->default_route.v4.mss = nm_ip4_config_get_mss (composite); + priv->default_route.v4_has = TRUE; + memset (&priv->default_route.v4, 0, sizeof (priv->default_route.v4)); + priv->default_route.v4.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v4.gateway = gateway; + priv->default_route.v4.metric = default_route_metric; + priv->default_route.v4.mss = nm_ip4_config_get_mss (composite); - if (!has_direct_route && commit) { - NMPlatformIP4Route r = priv->default_route.v4; + if (!has_direct_route) { + NMPlatformIP4Route r = priv->default_route.v4; - /* add a direct route to the gateway */ - r.network = gateway; - r.plen = 32; - r.gateway = 0; - nm_ip4_config_add_route (composite, &r); - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); + /* add a direct route to the gateway */ + r.network = gateway; + r.plen = 32; + r.gateway = 0; + nm_ip4_config_add_route (composite, &r); } END_ADD_DEFAULT_ROUTE: + if (priv->default_route.v4_is_assumed) { + /* If above does not explicitly assign a default route, we always pick up the + * default route based on what is currently configured. + * That means that even managed connections with never-default, can + * get a default route (if configured externally). + */ + priv->default_route.v4_has = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &priv->default_route.v4); + } + /* Allow setting MTU etc */ if (commit) { if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit) @@ -3741,6 +3751,7 @@ ip6_config_merge_and_apply (NMDevice *self, gboolean success; NMIP6Config *composite; gboolean has_direct_route; + const struct in6_addr *gateway; /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); @@ -3787,56 +3798,65 @@ ip6_config_merge_and_apply (NMDevice *self, priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; - if (!connection) + if (!commit) { + /* during a non-commit event, we always pickup whatever is configured. */ + goto END_ADD_DEFAULT_ROUTE; + } + + if (nm_device_uses_assumed_connection (self)) goto END_ADD_DEFAULT_ROUTE; - if ( !nm_device_uses_assumed_connection (self) - && nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) { - const struct in6_addr *gateway; - priv->default_route.v6_is_assumed = FALSE; + /* we are about to commit (for a non-assumed connection). Enforce whatever we have + * configured. */ + priv->default_route.v6_is_assumed = FALSE; - if (!nm_ip6_config_get_num_addresses (composite)) { - /* without addresses we can have no default route. */ - goto END_ADD_DEFAULT_ROUTE; - } + if ( !connection + || !nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) + goto END_ADD_DEFAULT_ROUTE; - gateway = nm_ip6_config_get_gateway (composite); - if (!gateway) - goto END_ADD_DEFAULT_ROUTE; + if (!nm_ip6_config_get_num_addresses (composite)) { + /* without addresses we can have no default route. */ + goto END_ADD_DEFAULT_ROUTE; + } + + gateway = nm_ip6_config_get_gateway (composite); + if (!gateway) + goto END_ADD_DEFAULT_ROUTE; - has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL; + has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL; - /* In the (!has_direct_route && !commit) case it is not clear whether - * adding the default route will succeed. Still give it a try and add it */ + priv->default_route.v6_has = TRUE; + memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6)); + priv->default_route.v6.source = NM_IP_CONFIG_SOURCE_USER; + priv->default_route.v6.gateway = *gateway; + priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self); + priv->default_route.v6.mss = nm_ip6_config_get_mss (composite); - priv->default_route.v6_has = TRUE; - memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6)); - priv->default_route.v6.source = NM_IP_CONFIG_SOURCE_USER; - priv->default_route.v6.gateway = *gateway; - priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self); - priv->default_route.v6.mss = nm_ip6_config_get_mss (composite); + if (!has_direct_route) { + NMPlatformIP6Route r = priv->default_route.v6; - if (!has_direct_route && commit) { - NMPlatformIP6Route r = priv->default_route.v6; - - /* add a direct route to the gateway */ - r.network = *gateway; - r.plen = 128; - r.gateway = in6addr_any; - nm_ip6_config_add_route (composite, &r); - } - } else { - /* For interfaces that are assumed and that have no default-route by configuration, we assume - * the default connection and pick up whatever is configured. */ - priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); + /* add a direct route to the gateway */ + r.network = *gateway; + r.plen = 128; + r.gateway = in6addr_any; + nm_ip6_config_add_route (composite, &r); } END_ADD_DEFAULT_ROUTE: + if (priv->default_route.v6_is_assumed) { + /* If above does not explicitly assign a default route, we always pick up the + * default route based on what is currently configured. + * That means that even managed connections with never-default, can + * get a default route (if configured externally). + */ + priv->default_route.v6_has = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &priv->default_route.v6); + } + nm_ip6_config_addresses_sort (composite, priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN); From bfe2fd271bb3d75dabec995b5af320492945d799 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 26 Jan 2015 17:29:25 +0100 Subject: [PATCH 08/12] core: fix nm_ip_config_intersect() only to remove addresses, routes and gateway Otherwise we remove the DNS configuration during platform events. Fixes: 557667df12fc05b76326d6406553985effeeb2ac (cherry picked from commit 11ccf949a331c77e14a0d4115c7242e8732878c8) --- src/nm-ip4-config.c | 48 +++++---------------------------------------- src/nm-ip6-config.c | 28 +++----------------------- 2 files changed, 8 insertions(+), 68 deletions(-) diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index b15fc229dc..4ca4b68f81 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -755,14 +755,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) i++; } - /* nameservers */ - for (i = 0; i < nm_ip4_config_get_num_nameservers (dst); ) { - idx = _nameservers_get_index (src, nm_ip4_config_get_nameserver (dst, i)); - if (idx < 0) - nm_ip4_config_del_nameserver (dst, i); - else - i++; - } + /* ignore nameservers */ /* default gateway */ if ( !nm_ip4_config_get_num_addresses (dst) @@ -778,41 +771,10 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) i++; } - /* domains */ - for (i = 0; i < nm_ip4_config_get_num_domains (dst); ) { - idx = _domains_get_index (src, nm_ip4_config_get_domain (dst, i)); - if (idx < 0) - nm_ip4_config_del_domain (dst, i); - else - i++; - } - - /* dns searches */ - for (i = 0; i < nm_ip4_config_get_num_searches (dst); ) { - idx = _searches_get_index (src, nm_ip4_config_get_search (dst, i)); - if (idx < 0) - nm_ip4_config_del_search (dst, i); - else - i++; - } - - /* NIS */ - for (i = 0; i < nm_ip4_config_get_num_nis_servers (dst); ) { - idx = _nis_servers_get_index (src, nm_ip4_config_get_nis_server (dst, i)); - if (idx < 0) - nm_ip4_config_del_nis_server (dst, i); - else - i++; - } - - /* WINS */ - for (i = 0; i < nm_ip4_config_get_num_wins (dst); ) { - idx = _wins_get_index (src, nm_ip4_config_get_wins (dst, i)); - if (idx < 0) - nm_ip4_config_del_wins (dst, i); - else - i++; - } + /* ignore domains */ + /* ignore dns searches */ + /* ignore NIS */ + /* ignore WINS */ g_object_thaw_notify (G_OBJECT (dst)); } diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 82c74eb1ec..0eb12f1745 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -822,14 +822,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) i++; } - /* nameservers */ - for (i = 0; i < nm_ip6_config_get_num_nameservers (dst); ) { - idx = _nameservers_get_index (src, nm_ip6_config_get_nameserver (dst, i)); - if (idx < 0) - nm_ip6_config_del_nameserver (dst, i); - else - i++; - } + /* ignore nameservers */ /* default gateway */ dst_tmp = nm_ip6_config_get_gateway (dst); @@ -850,23 +843,8 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) i++; } - /* domains */ - for (i = 0; i < nm_ip6_config_get_num_domains (src); ) { - idx = _domains_get_index (src, nm_ip6_config_get_domain (dst, i)); - if (idx < 0) - nm_ip6_config_del_domain (dst, i); - else - i++; - } - - /* dns searches */ - for (i = 0; i < nm_ip6_config_get_num_searches (src); i++) { - idx = _searches_get_index (src, nm_ip6_config_get_search (dst, i)); - if (idx < 0) - nm_ip6_config_del_search (dst, i); - else - i++; - } + /* ignore domains */ + /* ignore dns searches */ g_object_thaw_notify (G_OBJECT (dst)); } From acc230e3c8c7af42334b728366da624e95799e30 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Thu, 12 Mar 2015 07:03:01 +0100 Subject: [PATCH 09/12] device: unschedule ip update if we just scheduled ip configuration It would subtract the configuration from device confguration that's not yet applied. This a the race where the loose the address while activating a connection that has both IPv6 and IPv4 configuration. Fixes: 557667df12fc05b76326d6406553985effeeb2ac https://bugzilla.gnome.org/show_bug.cgi?id=746066 (cherry picked from commit 2e99ddb7a7e65e74846d344b456c4ab4f2ce2ba7) --- src/devices/nm-device.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index d928389554..d228d6d373 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5625,6 +5625,7 @@ nm_device_activate_schedule_ip4_config_result (NMDevice *self, NMIP4Config *conf if (config) priv->dev_ip4_config = g_object_ref (config); + nm_device_queued_ip_config_change_clear (self); activation_source_schedule (self, nm_device_activate_ip4_config_commit, AF_INET); _LOGD (LOGD_DEVICE | LOGD_IP4, "Activation: Stage 5 of 5 (IPv4 Configure Commit) scheduled..."); From 29f13ecf66570d4f9240224998325ddf20bfc95b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 7 May 2015 10:46:58 +0200 Subject: [PATCH 10/12] device: fix configuring static ip addresses When a connection had static IP addresses, an early event from plaform would clear them from priv->con_ip4_config. Fix that, by don't initializing priv->con_ip4_config before we commit the first time. https://bugzilla.gnome.org/show_bug.cgi?id=749052 Fixes: 557667df12fc05b76326d6406553985effeeb2ac (cherry picked from commit 843205521fd45ee5e73b26696cc5f6b82853709c) --- src/devices/nm-device.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index d228d6d373..c101185830 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3179,7 +3179,8 @@ ip4_config_merge_and_apply (NMDevice *self, composite = nm_ip4_config_new (); - ensure_con_ipx_config (self); + if (commit) + ensure_con_ipx_config (self); if (priv->dev_ip4_config) nm_ip4_config_merge (composite, priv->dev_ip4_config); @@ -3756,7 +3757,8 @@ ip6_config_merge_and_apply (NMDevice *self, /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); - ensure_con_ipx_config (self); + if (commit) + ensure_con_ipx_config (self); /* Merge all the IP configs into the composite config */ if (priv->ac_ip6_config) @@ -6991,7 +6993,6 @@ update_ip_config (NMDevice *self, gboolean 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 @@ -7030,8 +7031,6 @@ update_ip_config (NMDevice *self, gboolean initial) 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 From d9dac7ab4cd9c98fdf0fb856b587411ee2b598cf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 13 May 2015 21:21:49 +0200 Subject: [PATCH 11/12] default-route: for devices with 'never-default' enforce the default-route only once Since da708059dabb2854d11eed1a403398327b31535b, we would pickup the default-route as configured externally, except at those moments when NM re-applys the IP configuration of the interface, such as during a DHCP lease. That allows the user to add/remove the default-route externally (iproute). But still, at random times (DHCP lease), we will revert those external changes. Extend this, that if the connection is explicitly configured as 'never-default=yes', that it tells NM not to interfere with externally added default-routes on this device. That means, NM will only remove any preexisting default-routes when configuring the device a first time. On any later attempts, NM will assume whatever is configured there. That makes sense because the user indicated not wanting NM to manage a default-route on that device, so if something externally added a default-route, assume that is what the user wants. This only affects non-assumed connections, with 'never-default=yes'. https://bugzilla.redhat.com/show_bug.cgi?id=1205405 (cherry picked from commit 98e50e358bde29a78d7a9547a21736aa143cd04b) --- src/devices/nm-device.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index c101185830..eba15a32d5 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -257,9 +257,11 @@ typedef struct { struct { gboolean v4_has; gboolean v4_is_assumed; + gboolean v4_configure_first_time; NMPlatformIP4Route v4; gboolean v6_has; gboolean v6_is_assumed; + gboolean v6_configure_first_time; NMPlatformIP6Route v6; } default_route; @@ -3170,6 +3172,7 @@ ip4_config_merge_and_apply (NMDevice *self, gboolean has_direct_route; const guint32 default_route_metric = nm_device_get_ip4_route_metric (self); guint32 gateway; + gboolean connection_has_default_route, connection_is_never_default; /* Merge all the configs into the composite config */ if (config) { @@ -3227,13 +3230,24 @@ ip4_config_merge_and_apply (NMDevice *self, if (nm_device_uses_assumed_connection (self)) goto END_ADD_DEFAULT_ROUTE; + connection_has_default_route + = nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), + connection, &connection_is_never_default); + + if ( !priv->default_route.v4_configure_first_time + && connection_is_never_default) { + /* If the connection is explicitly configured as never-default, we enforce the (absense of the) + * default-route only once. That allows the user to configure a connection as never-default, + * but he can add default routes externally (via a dispatcher script) and NM will not interfere. */ + goto END_ADD_DEFAULT_ROUTE; + } /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ + priv->default_route.v4_configure_first_time = FALSE; priv->default_route.v4_is_assumed = FALSE; - if ( !connection - || !nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) + if (!connection_has_default_route) goto END_ADD_DEFAULT_ROUTE; if (!nm_ip4_config_get_num_addresses (composite)) { @@ -3753,6 +3767,7 @@ ip6_config_merge_and_apply (NMDevice *self, NMIP6Config *composite; gboolean has_direct_route; const struct in6_addr *gateway; + gboolean connection_has_default_route, connection_is_never_default; /* If no config was passed in, create a new one */ composite = nm_ip6_config_new (); @@ -3808,13 +3823,24 @@ ip6_config_merge_and_apply (NMDevice *self, if (nm_device_uses_assumed_connection (self)) goto END_ADD_DEFAULT_ROUTE; + connection_has_default_route + = nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), + connection, &connection_is_never_default); + + if ( !priv->default_route.v6_configure_first_time + && connection_is_never_default) { + /* If the connection is explicitly configured as never-default, we enforce the (absence of the) + * default-route only once. That allows the user to configure a connection as never-default, + * but he can add default routes externally (via a dispatcher script) and NM will not interfere. */ + goto END_ADD_DEFAULT_ROUTE; + } /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ + priv->default_route.v6_configure_first_time = FALSE; priv->default_route.v6_is_assumed = FALSE; - if ( !connection - || !nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, NULL)) + if (!connection_has_default_route) goto END_ADD_DEFAULT_ROUTE; if (!nm_ip6_config_get_num_addresses (composite)) { @@ -7632,8 +7658,10 @@ _cleanup_generic_post (NMDevice *self, gboolean deconfigure) priv->default_route.v4_has = FALSE; priv->default_route.v4_is_assumed = TRUE; + priv->default_route.v4_configure_first_time = TRUE; priv->default_route.v6_has = FALSE; priv->default_route.v6_is_assumed = TRUE; + priv->default_route.v6_configure_first_time = TRUE; nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self); nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); @@ -8573,7 +8601,9 @@ nm_device_init (NMDevice *self) priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free); priv->default_route.v4_is_assumed = TRUE; + priv->default_route.v4_configure_first_time = TRUE; priv->default_route.v6_is_assumed = TRUE; + priv->default_route.v6_configure_first_time = TRUE; } static GObject* From c38ff0b083f0ce3811ac0fa506f62739ed02c425 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 27 May 2015 11:52:39 +0200 Subject: [PATCH 12/12] default-route: also configure default-routes for assumed connections Previously for assumed connections we would never configure a default route. That has serious problems for example in the following two scenarios: - the default-route might have a limited lifetime from a previous SLAAC/accept_ra setting. In this case, once we assume the connection we must also ensure that we extend the lifetime of the default route. - the gateway could be received via DHCP/RA and it might change. If we ignore default-routes for assumed connection we miss that change. The problem is that the notion of "assumed connection" wrongly combines two conflicting goals (related bug bgo#746440): a) have an external device that is entirely unmanged by NM. b) do a seamless takeover of a previously managed connection at start, but still fully manage. This patch changes the handling of default-routes towards meaning b). https://bugzilla.redhat.com/show_bug.cgi?id=1224291 (cherry picked from commit d51975ed921a5876b76e081b8f3df4e2ca1f1ca9) --- src/devices/nm-device.c | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index eba15a32d5..845205b45c 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -3198,7 +3198,7 @@ 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. For assumed connection, + /* Merge user overrides into the composite config. For assumed connections, * con_ip4_config is empty. */ if (priv->con_ip4_config) nm_ip4_config_merge (composite, priv->con_ip4_config); @@ -3227,14 +3227,12 @@ ip4_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } - if (nm_device_uses_assumed_connection (self)) - goto END_ADD_DEFAULT_ROUTE; - connection_has_default_route = nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection, &connection_is_never_default); if ( !priv->default_route.v4_configure_first_time + && !nm_device_uses_assumed_connection (self) && connection_is_never_default) { /* If the connection is explicitly configured as never-default, we enforce the (absense of the) * default-route only once. That allows the user to configure a connection as never-default, @@ -3242,6 +3240,11 @@ ip4_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } + /* At this point, we treat assumed and non-assumed connections alike. + * For assumed connections we do that because we still manage RA and DHCP + * leases for them, so we must extend/update the default route on commits. + */ + /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ priv->default_route.v4_configure_first_time = FALSE; @@ -3820,14 +3823,12 @@ ip6_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } - if (nm_device_uses_assumed_connection (self)) - goto END_ADD_DEFAULT_ROUTE; - connection_has_default_route = nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection, &connection_is_never_default); if ( !priv->default_route.v6_configure_first_time + && !nm_device_uses_assumed_connection (self) && connection_is_never_default) { /* If the connection is explicitly configured as never-default, we enforce the (absence of the) * default-route only once. That allows the user to configure a connection as never-default, @@ -3835,6 +3836,11 @@ ip6_config_merge_and_apply (NMDevice *self, goto END_ADD_DEFAULT_ROUTE; } + /* At this point, we treat assumed and non-assumed connections alike. + * For assumed connections we do that because we still manage RA and DHCP + * leases for them, so we must extend/update the default route on commits. + */ + /* we are about to commit (for a non-assumed connection). Enforce whatever we have * configured. */ priv->default_route.v6_configure_first_time = FALSE;