diff options
author | Thomas Haller <thaller@redhat.com> | 2014-11-03 11:21:46 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2014-11-05 23:55:07 +0100 |
commit | 3b02c41a54722e7eaa2a73ac4a5ad941d1466041 (patch) | |
tree | a56727529313eeeac558d29516ead2d4e7b2fc31 | |
parent | a1720e4cf7a9b903508fdfe6e8469ea77988f96e (diff) | |
download | NetworkManager-3b02c41a54722e7eaa2a73ac4a5ad941d1466041.tar.gz |
fixup! core: add manager for default route and support multiple default routes
-rw-r--r-- | src/devices/nm-device.c | 170 | ||||
-rw-r--r-- | src/nm-default-route-manager.c | 245 | ||||
-rw-r--r-- | src/nm-default-route-manager.h | 4 | ||||
-rw-r--r-- | src/nm-policy.c | 82 |
4 files changed, 291 insertions, 210 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index f658563f7b..6f4c4db4b6 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2639,6 +2639,52 @@ aipd_start (NMDevice *self, NMDeviceStateReason *reason) } /*********************************************/ + +static gboolean +_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route) +{ + gboolean success = FALSE; + int ifindex = nm_device_get_ip_ifindex (self); + GArray *routes; + + if (addr_family == AF_INET) + routes = nm_platform_ip4_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + else + routes = nm_platform_ip6_route_get_all (ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); + + if (routes) { + guint route_metric = G_MAXUINT32, m; + const NMPlatformIPRoute *route = NULL, *r; + guint i; + + /* if there are several default routes, find the one with the best metric */ + for (i = 0; i < routes->len; i++) { + if (addr_family == AF_INET) { + r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i); + m = r->metric; + } else { + r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i); + m = nm_utils_ip6_route_metric_normalize (r->metric); + } + if (!route || m < route_metric) { + route = r; + route_metric = m; + } + } + + if (route) { + if (addr_family == AF_INET) + *((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route); + else + *((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route); + success = TRUE; + } + g_array_free (routes, TRUE); + } + return success; +} + +/*********************************************/ /* DHCPv4 stuff */ static void @@ -2704,10 +2750,7 @@ ip4_config_merge_and_apply (NMDevice *self, */ connection = nm_device_get_connection (self); if (connection) { - NMSettingIP4Config *s_ip4; - guint32 route_metric, mss; - guint32 gw_addr; - NMPlatformIP4Route route; + gboolean assumed = nm_device_uses_assumed_connection (self); if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { nm_ip4_config_merge_setting (composite, @@ -2716,32 +2759,37 @@ ip4_config_merge_and_apply (NMDevice *self, } /* add the default route */ - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if ( s_ip4 - && !nm_setting_ip4_config_get_never_default (s_ip4) - && (gw_addr = nm_ip4_config_get_gateway (composite)) - && (nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM)) { - route_metric = nm_device_get_ip4_route_metric (self); - mss = nm_ip4_config_get_mss (composite); - - memset (&route, 0, sizeof (route)); - route.source = NM_IP_CONFIG_SOURCE_USER; - route.network = 0; - route.plen = 0; - route.gateway = gw_addr; - route.metric = route_metric; - route.mss = mss; - - nm_ip4_config_add_route (composite, &route); - if ( gw_addr - && !nm_ip4_config_get_direct_route_for_host (composite, gw_addr) - && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - /* To configure a route via gateway, the gateway must be directly reachable. - * Add this route too. */ - route.network = gw_addr; - route.plen = 32; - route.gateway = 0; + if (nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), connection)) { + guint32 gateway = 0; + gboolean to_add = FALSE; + NMPlatformIP4Route route = { 0 }; + + if (assumed) + to_add = _device_get_default_route_from_platform (self, AF_INET, (NMPlatformIPRoute *) &route); + else { + gateway = nm_ip4_config_get_gateway (composite); + if ( gateway + || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) { + route.source = NM_IP_CONFIG_SOURCE_USER; + route.gateway = gateway; + route.metric = nm_device_get_ip4_route_metric (self); + route.mss = nm_ip4_config_get_mss (composite); + to_add = TRUE; + } + } + + if (to_add) { nm_ip4_config_add_route (composite, &route); + if ( !assumed + && gateway + && !nm_ip4_config_get_direct_route_for_host (composite, route.gateway)) { + /* To configure a route via gateway, the gateway must be directly reachable. + * Add this route too. */ + route.network = gateway; + route.plen = 32; + route.gateway = 0; + nm_ip4_config_add_route (composite, &route); + } } } } @@ -3242,10 +3290,7 @@ ip6_config_merge_and_apply (NMDevice *self, */ connection = nm_device_get_connection (self); if (connection) { - NMSettingIP6Config *s_ip6; - guint32 route_metric, mss; - const struct in6_addr *gw_addr; - NMPlatformIP6Route route; + gboolean assumed = nm_device_uses_assumed_connection (self); if (!nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { nm_ip6_config_merge_setting (composite, @@ -3254,32 +3299,37 @@ ip6_config_merge_and_apply (NMDevice *self, } /* add the default route */ - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if ( s_ip6 - && !nm_setting_ip6_config_get_never_default (s_ip6) - && (gw_addr = nm_ip6_config_get_gateway (composite)) - && (nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM)) { - route_metric = nm_device_get_ip6_route_metric (self); - mss = nm_ip6_config_get_mss (composite); - - memset (&route, 0, sizeof (route)); - route.source = NM_IP_CONFIG_SOURCE_USER; - route.network = in6addr_any; - route.plen = 0; - route.gateway = gw_addr ? *gw_addr : in6addr_any; - route.metric = route_metric; - route.mss = mss; - - nm_ip6_config_add_route (composite, &route); - if ( gw_addr - && !nm_ip6_config_get_direct_route_for_host (composite, gw_addr) - && !nm_settings_connection_get_nm_generated_assumed (NM_SETTINGS_CONNECTION (connection))) { - /* To configure a route via gateway, the gateway must be directly reachable. - * Add this route too. */ - route.network = *gw_addr; - route.plen = 128; - route.gateway = in6addr_any; + if (nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), connection)) { + const struct in6_addr *gateway = NULL; + gboolean to_add = FALSE; + NMPlatformIP6Route route = { 0 }; + + if (assumed) + to_add = _device_get_default_route_from_platform (self, AF_INET6, (NMPlatformIPRoute *) &route); + else { + gateway = nm_ip6_config_get_gateway (composite); + if ( gateway + || nm_device_get_device_type (self) == NM_DEVICE_TYPE_MODEM) { + 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); + to_add = TRUE; + } + } + + if (to_add) { nm_ip6_config_add_route (composite, &route); + if ( !assumed + && gateway + && !nm_ip6_config_get_direct_route_for_host (composite, gateway)) { + /* To configure a route via gateway, the gateway must be directly reachable. + * Add this route too. */ + route.network = *gateway; + route.plen = 128; + route.gateway = in6addr_any; + nm_ip6_config_add_route (composite, &route); + } } } } @@ -5479,8 +5529,6 @@ nm_device_set_ip4_config (NMDevice *self, g_clear_object (&priv->dev_ip4_config); } - /* FIXME: nm_default_route_manager_ip4_update_default_route() does not modify the device if it is assumed. - * Is that sufficient for the !commit case? */ nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), self); if (has_changes) { @@ -5604,8 +5652,6 @@ nm_device_set_ip6_config (NMDevice *self, nm_ip6_config_get_dbus_path (old_config)); } - /* FIXME: nm_default_route_manager_ip6_update_default_route() does not modify the device if it is assumed. - * Is that sufficient for the !commit case? */ nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), self); if (has_changes) { diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index cce202c14b..85ffc3f7d9 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -130,55 +130,89 @@ _entry_find_by_device (GPtrArray *entries, NMDevice *device, guint *out_idx) return NULL; } +static Entry * +_entry_find (const VTableIP *vtable, GPtrArray *entries, const Entry *skip_entry, int ifindex, gint64 effective_metric, guint *out_idx) +{ + guint i; + if (effective_metric >= 0) + effective_metric = vtable->route_metric_normalize (effective_metric); + + for (i = 0; i < entries->len; i++) { + Entry *entry = g_ptr_array_index (entries, i); + + if (entry == skip_entry) + continue; + if (ifindex > 0 && entry->route.ifindex != ifindex) + continue; + if (effective_metric >= 0 && effective_metric != vtable->route_metric_normalize (entry->effective_metric)) + continue; + if (out_idx) + *out_idx = i; + return entry; + } + if (out_idx) + *out_idx = G_MAXUINT; + return NULL; +} + static void _platform_route_sync (const VTableIP *vtable, NMDefaultRouteManager *self, Entry *entry) { + NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); GArray *routes; guint i; gboolean success; + GPtrArray *entries; g_assert (entry->synced); - if (VTABLE_IS_IP4) { - success = nm_platform_ip4_route_add (entry->route.ifindex, - entry->route.source, - 0, - 0, - entry->route4.gateway, - entry->effective_metric, - entry->route.mss); - } else { - success = nm_platform_ip6_route_add (entry->route.ifindex, - entry->route.source, - in6addr_any, - 0, - entry->route6.gateway, - entry->effective_metric, - entry->route.mss); - } - if (!success) - _LOGW (vtable->addr_family, " failed to add default route %s", vtable->platform_route_to_string (&entry->route)); + entries = vtable->get_entries (priv); + + /* only touch the route if no other entry already exists with a comparable + * route. This works, because we always touch one entry at a time and assume + * that all other entries are properly synced. Hence, if we find another + * entry with the same route, there is nothing to do. */ + if (!_entry_find (vtable, entries, entry, -1, entry->effective_metric, NULL)) { + if (VTABLE_IS_IP4) { + success = nm_platform_ip4_route_add (entry->route.ifindex, + entry->route.source, + 0, + 0, + entry->route4.gateway, + entry->effective_metric, + entry->route.mss); + } else { + success = nm_platform_ip6_route_add (entry->route.ifindex, + entry->route.source, + in6addr_any, + 0, + entry->route6.gateway, + entry->effective_metric, + entry->route.mss); + } + if (!success) + _LOGW (vtable->addr_family, " failed to add default route %s", vtable->platform_route_to_string (&entry->route)); + } else + _LOGD (vtable->addr_family, " don't add default route %s because of existing entry", vtable->platform_route_to_string (&entry->route)); /* prune all other default routes from this device. */ if (VTABLE_IS_IP4) { - routes = nm_platform_ip4_route_get_all (entry->route.ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + routes = nm_platform_ip4_route_get_all (entry->route.ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); for (i = 0; i < routes->len; i++) { const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); - if ( route->gateway != entry->route4.gateway - || route->metric != route->metric) { + if ( route->metric != entry->effective_metric + && !_entry_find (vtable, entries, NULL, -1, route->metric, NULL)) vtable->platform_route_delete_default (entry->route.ifindex, route->metric); - } } } else { - routes = nm_platform_ip6_route_get_all (entry->route.ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT); + routes = nm_platform_ip6_route_get_all (entry->route.ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT); for (i = 0; i < routes->len; i++) { const NMPlatformIP6Route *route = &g_array_index (routes, NMPlatformIP6Route, i); - if ( !IN6_ARE_ADDR_EQUAL (&route->gateway, &entry->route6.gateway) - || route->metric != entry->effective_metric) { + if ( route->metric != entry->effective_metric + && !_entry_find (vtable, entries, NULL, -1, route->metric, NULL)) vtable->platform_route_delete_default (entry->route.ifindex, route->metric); - } } } g_array_free (routes, TRUE); @@ -216,7 +250,7 @@ _sort_entries_cmp (gconstpointer a, gconstpointer b, gpointer user_data) * we don't reorder either. */ if (!!e_a->synced != !!e_b->synced) - return e_a->synced ? -1 : 1; + return e_a->synced ? 1 : -1; /* otherwise, do not reorder */ return 0; @@ -267,62 +301,63 @@ _resync_metric_of_entry (const VTableIP *vtable, NMDefaultRouteManager *self, gu old_metric = entry->effective_metric; entry->effective_metric = new_metric; - _LOGD (vtable->addr_family, "entry [%u/%p]: resync metric %s (was %u)%s", entry_idx, entry->device, vtable->platform_route_to_string (&entry->route), (guint) old_metric, do_sync?"":" (inform)"); + _LOGD (vtable->addr_family, "entry [%u/%p]: resync metric %s (%u -> %u)%s", entry_idx, entry->device, vtable->platform_route_to_string (&entry->route), (guint) old_metric, (guint) new_metric, do_sync?"":" (inform)"); if (do_sync) _platform_route_sync (vtable, self, entry); } -static gboolean -_readjust_all_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *entry_ignored, gboolean do_sync) +static void +_readjust_all_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *entry_not_sync, gboolean do_sync) { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); Entry *entry0, *entry; guint i; - gboolean changed = FALSE; - guint32 expected_metric; + guint32 expected_metric, last_metric; GPtrArray *entries; entries = vtable->get_entries (priv); if (entries->len == 0) - return FALSE; + return; entry0 = g_ptr_array_index (entries, 0); if ( entry0->synced - && entry0 != entry_ignored + && entry0 != entry_not_sync && entry0->effective_metric != entry0->route.metric) { /* adjust the metric of the leading entry */ _resync_metric_of_entry (vtable, self, 0, entry0->route.metric, do_sync); - changed = TRUE; } + last_metric = entry0->effective_metric; for (i = 1; i < entries->len; i++) { entry = g_ptr_array_index (entries, i); - if (entry == entry_ignored) - continue; - if (!entry->synced) + if (!entry->synced) { + last_metric = MAX (last_metric, entry->effective_metric); continue; + } expected_metric = entry->route.metric; - if ( expected_metric != G_MAXUINT32 - && expected_metric == entry0->effective_metric) - expected_metric++; + if (expected_metric <= last_metric) + expected_metric = last_metric == G_MAXUINT32 ? G_MAXUINT32 : last_metric + 1; + last_metric = expected_metric; if (expected_metric != entry->effective_metric) { - /* the entry must be resynced to adjust the metric */ - _resync_metric_of_entry (vtable, self, i, expected_metric, do_sync); - changed = TRUE; + if (entry == entry_not_sync) + entry->effective_metric = expected_metric; + else { + /* the entry must be resynced to adjust the metric */ + _resync_metric_of_entry (vtable, self, i, expected_metric, do_sync); + } } } - return changed; } static void _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx, const Entry *old_entry, gboolean do_sync) { NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self); - Entry *entry, *entry0; + Entry *entry; gboolean first_entry_changed, entries_resorted; NMDevice *device; GPtrArray *entries; @@ -337,7 +372,7 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint || (entry->device == old_entry->device && entry->route.ifindex == old_entry->route.ifindex)); /* if the device uses an assumed connection, we don't sync the route. */ - entry->synced = !nm_device_uses_generated_assumed_connection (device); + entry->synced = !nm_device_uses_assumed_connection (device); entry->effective_metric = entry->route.metric; _LOGD (vtable->addr_family, "entry[%u/%p]: %s %s%s", entry_idx, entry->device, old_entry ? "update" : "add", vtable->platform_route_to_string (&entry->route), entry->synced ? "" : "(no sync)"); @@ -348,21 +383,12 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint */ entries_resorted = _sort_entries (vtable, entries, &first_entry_changed); - if (first_entry_changed || entry_idx == 0) { - /* the first entry changed. It means, that we potentially - * have to adjust the following device routes (by adjusting the metric). */ - _readjust_all_metrics (vtable, self, entry, do_sync); - } + /* the first entry changed. It means, that we potentially + * have to adjust the following device routes (by adjusting the metric). */ + _readjust_all_metrics (vtable, self, entry, do_sync); - entry0 = g_ptr_array_index (entries, 0); - - if ( entry->synced - && entry != entry0 - && entry->route.metric != G_MAXUINT32 - && entry->route.metric == entry0->route.metric) { - _LOGD (vtable->addr_family, "entry[%u/%p]: adjust effective metric for %s to %d", entry_idx, entry->device, vtable->platform_route_to_string (&entry->route), (int) entry->route.metric + 1); - entry->effective_metric = entry->route.metric + 1; - } + if (entry->effective_metric != entry->route.metric) + _LOGD (vtable->addr_family, "entry[%u/%p]: adjust effective metric for %s to %d", entry_idx, entry->device, vtable->platform_route_to_string (&entry->route), (guint) entry->effective_metric); if (do_sync) _platform_route_sync (vtable, self, entry); @@ -389,14 +415,20 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint g_ptr_array_index (entries, entry_idx) = NULL; g_ptr_array_remove_index (entries, entry_idx); - if (entry_idx == 0) { - /* The first entry was deleted. Now there is a new default route, - * adjust the remaining metrics. */ - _readjust_all_metrics (vtable, self, NULL, do_sync); - } + /* The first entry was deleted. Now there is a new default route, + * adjust the remaining metrics. */ + _readjust_all_metrics (vtable, self, NULL, do_sync); - if (do_sync && entry->synced) - vtable->platform_route_delete_default (entry->route.ifindex, entry->effective_metric); + if (do_sync && entry->synced) { + Entry *conflicting_entry = _entry_find (vtable, entries, NULL, -1, entry->effective_metric, NULL); + if (conflicting_entry) { + /* there is another entry with the same route we are about to delete. Re-sync it. */ + if (conflicting_entry->synced) + _platform_route_sync (vtable, self, conflicting_entry); + } else { + vtable->platform_route_delete_default (entry->route.ifindex, entry->effective_metric); + } + } g_signal_emit (self, signals[SIGNAL_CHANGED], 0, vtable->addr_family, (gboolean) (entry_idx == 0)); @@ -437,7 +469,6 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx; const NMPlatformIPRoute *default_route = NULL; int ip_ifindex; - guint i; GPtrArray *entries; g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self)); @@ -463,38 +494,19 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, g_object_thaw_notify (G_OBJECT (self)); return; } - if (!entry) { - /* Not only every device must appear only once in the list, but its ip_ifindex too... */ - for (i = 0; i < entries->len; i++) { - Entry *e = g_ptr_array_index (entries, i); - - if (e->route.ifindex == ip_ifindex) { - _LOGE (vtable->addr_family, "duplicate ifindex %d of device %p/%s (%u, %s)", ip_ifindex, device, nm_device_get_iface (device), i, vtable->platform_route_to_string (&e->route)); - return; - } - } - } /* get the @default_route from the device. */ if (ip_ifindex > 0) { if (VTABLE_IS_IP4) { NMIP4Config *config; - if ( (config = nm_device_get_ip4_config (device)) - && nm_ip4_config_get_gateway (config) - && nm_device_get_device_type (device) != NM_DEVICE_TYPE_MODEM - && !nm_ip4_config_get_never_default (config)) { + if ((config = nm_device_get_ip4_config (device))) default_route = (const NMPlatformIPRoute *) nm_ip4_config_get_default_route (config); - } } else { NMIP6Config *config; - if ( (config = nm_device_get_ip6_config (device)) - && nm_ip6_config_get_gateway (config) - && nm_device_get_device_type (device) != NM_DEVICE_TYPE_MODEM - && !nm_ip6_config_get_never_default (config)) { + if ((config = nm_device_get_ip6_config (device))) default_route = (const NMPlatformIPRoute *) nm_ip6_config_get_default_route (config); - } } } g_assert (!default_route || default_route->plen == 0); @@ -620,6 +632,57 @@ nm_default_route_manager_ip6_get_effective_metric (NMDefaultRouteManager *self, /***********************************************************************************/ +static gboolean +_ipx_connection_has_default_route (const VTableIP *vtable, NMDefaultRouteManager *self, NMConnection *connection) +{ + const char *method; + + g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + + if (VTABLE_IS_IP4) { + NMSettingIP4Config *s_ip = nm_connection_get_setting_ip4_config (connection); + + if (!s_ip || nm_setting_ip4_config_get_never_default (s_ip)) + return FALSE; + } else { + NMSettingIP6Config *s_ip = nm_connection_get_setting_ip6_config (connection); + + if (!s_ip || nm_setting_ip6_config_get_never_default (s_ip)) + return FALSE; + } + + if (VTABLE_IS_IP4) { + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); + if ( !method + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) + || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) + return FALSE; + } else { + method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); + if ( !method + || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) + || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) + return FALSE; + } + + return TRUE; +} + +gboolean +nm_default_route_manager_ip4_connection_has_default_route (NMDefaultRouteManager *self, NMConnection *connection) +{ + return _ipx_connection_has_default_route (&vtable_ip4, self, connection); +} + +gboolean +nm_default_route_manager_ip6_connection_has_default_route (NMDefaultRouteManager *self, NMConnection *connection) +{ + return _ipx_connection_has_default_route (&vtable_ip6, self, connection); +} + +/***********************************************************************************/ + static GPtrArray * _v4_get_entries (NMDefaultRouteManagerPrivate *priv) { diff --git a/src/nm-default-route-manager.h b/src/nm-default-route-manager.h index 64862a4538..e5dec4ee17 100644 --- a/src/nm-default-route-manager.h +++ b/src/nm-default-route-manager.h @@ -20,6 +20,7 @@ #include <glib-object.h> +#include "nm-connection.h" #include "nm-types.h" #ifndef __NETWORKMANAGER_DEFAULT_ROUTE_MANAGER_H__ @@ -58,5 +59,8 @@ void nm_default_route_manager_ip6_remove_default_route (NMDefaultRouteManager *m gint64 nm_default_route_manager_ip4_get_effective_metric (NMDefaultRouteManager *manager, NMDevice *device); gint64 nm_default_route_manager_ip6_get_effective_metric (NMDefaultRouteManager *manager, NMDevice *device); +gboolean nm_default_route_manager_ip4_connection_has_default_route (NMDefaultRouteManager *manager, NMConnection *connection); +gboolean nm_default_route_manager_ip6_connection_has_default_route (NMDefaultRouteManager *manager, NMConnection *connection); + #endif /* NM_DEFAULT_ROUTE_MANAGER_H */ diff --git a/src/nm-policy.c b/src/nm-policy.c index c04ee0067c..c9686eff8d 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -108,11 +108,7 @@ get_best_ip4_device (NMPolicy *self, gboolean fully_activated) for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMDeviceState state = nm_device_get_state (dev); - NMActRequest *req; - NMConnection *connection; - NMSettingIP4Config *s_ip4; - gint64 prio = -1; - const char *method = NULL; + guint32 prio; if ( state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) @@ -121,32 +117,19 @@ get_best_ip4_device (NMPolicy *self, gboolean fully_activated) if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES) continue; - req = nm_device_get_act_request (dev); - g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); - - method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP4_CONFIG); - /* If IPv4 is disabled or link-local-only, it can't be the default */ - if ( !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_DISABLED) - || !strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_LINK_LOCAL)) - continue; - - /* 'never-default' devices can't ever be the default */ - s_ip4 = nm_connection_get_setting_ip4_config (connection); - g_assert (s_ip4); - if (nm_setting_ip4_config_get_never_default (s_ip4)) + if (!nm_default_route_manager_ip4_connection_has_default_route (nm_default_route_manager_get (), + nm_device_get_connection (dev))) continue; if (fully_activated) { - prio = nm_default_route_manager_ip4_get_effective_metric (nm_default_route_manager_get (), dev); - g_assert (prio >= -1 && prio <= G_MAXUINT32); - if (prio == -1) + gint64 effective_metric = nm_default_route_manager_ip4_get_effective_metric (nm_default_route_manager_get (), dev); + + if (effective_metric == -1) continue; - } + prio = (guint32) effective_metric; + } else + prio = nm_device_get_ip6_route_metric (dev); - if (prio < 0) - prio = nm_device_get_ip4_route_metric (dev); if ( prio < best_prio || (priv->default_device4 == dev && prio == best_prio) || !best) { @@ -183,11 +166,7 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) for (iter = nm_manager_get_devices (priv->manager); iter; iter = g_slist_next (iter)) { NMDevice *dev = NM_DEVICE (iter->data); NMDeviceState state = nm_device_get_state (dev); - NMActRequest *req; - NMConnection *connection; - NMSettingIP6Config *s_ip6; - gint64 prio = -1; - const char *method = NULL; + guint32 prio; if ( state <= NM_DEVICE_STATE_DISCONNECTED || state >= NM_DEVICE_STATE_DEACTIVATING) @@ -196,31 +175,18 @@ get_best_ip6_device (NMPolicy *self, gboolean fully_activated) if (fully_activated && state < NM_DEVICE_STATE_SECONDARIES) continue; - req = nm_device_get_act_request (dev); - g_assert (req); - connection = nm_act_request_get_connection (req); - g_assert (connection); - - method = nm_utils_get_ip_config_method (connection, NM_TYPE_SETTING_IP6_CONFIG); - if ( !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_IGNORE) - || !strcmp (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - continue; - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - g_assert (s_ip6); - if (nm_setting_ip6_config_get_never_default (s_ip6)) + if (!nm_default_route_manager_ip6_connection_has_default_route (nm_default_route_manager_get (), + nm_device_get_connection (dev))) continue; if (fully_activated) { - prio = nm_default_route_manager_ip6_get_effective_metric (nm_default_route_manager_get (), dev); - g_assert (prio >= -1 && prio <= G_MAXUINT32); - if (prio == -1) - continue; - } + gint64 effective_metric = nm_default_route_manager_ip6_get_effective_metric (nm_default_route_manager_get (), dev); - if (prio < 0) + if (effective_metric == -1) + continue; + prio = (guint32) effective_metric; + } else prio = nm_device_get_ip6_route_metric (dev); - prio = nm_utils_ip6_route_metric_normalize (prio); if ( prio < best_prio @@ -651,6 +617,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) if (vpn) { in_addr_t int_gw = nm_vpn_connection_get_ip4_internal_gateway (vpn); int mss = nm_ip4_config_get_mss (ip4_config); + guint32 route_metric = nm_vpn_connection_get_ip4_route_metric (vpn); /* If no VPN interface, use the parent interface */ if (ip_ifindex <= 0) @@ -658,14 +625,14 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update) if (!nm_platform_ip4_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, 0, 0, int_gw, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + route_metric, mss)) { if (int_gw) { (void) nm_platform_ip4_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, int_gw, 32, 0, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss); + route_metric, mss); if (!nm_platform_ip4_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, 0, 0, int_gw, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) + route_metric, mss)) nm_log_err (LOGD_IP4 | LOGD_VPN, "Failed to set IPv4 default route via VPN."); } else nm_log_err (LOGD_IP4 | LOGD_VPN, "Failed to set IPv4 default route via VPN."); @@ -836,6 +803,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) if (vpn) { const struct in6_addr *int_gw = nm_vpn_connection_get_ip6_internal_gateway (vpn); int mss = nm_ip6_config_get_mss (ip6_config); + guint32 route_metric = nm_vpn_connection_get_ip6_route_metric (vpn); if (!int_gw) int_gw = &in6addr_any; @@ -846,14 +814,14 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update) if (!nm_platform_ip6_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, in6addr_any, 0, *int_gw, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) { + route_metric, mss)) { if (!IN6_IS_ADDR_UNSPECIFIED (int_gw)) { (void) nm_platform_ip6_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, *int_gw, 128, in6addr_any, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss); + route_metric, mss); if (!nm_platform_ip6_route_add (ip_ifindex, NM_IP_CONFIG_SOURCE_VPN, in6addr_any, 0, *int_gw, - NM_PLATFORM_ROUTE_METRIC_DEFAULT, mss)) + route_metric, mss)) nm_log_err (LOGD_IP6 | LOGD_VPN, "Failed to set IPv6 default route via VPN."); } else nm_log_err (LOGD_IP6 | LOGD_VPN, "Failed to set IPv6 default route via VPN."); |