summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-11-03 11:21:46 +0100
committerThomas Haller <thaller@redhat.com>2014-11-05 23:55:07 +0100
commit3b02c41a54722e7eaa2a73ac4a5ad941d1466041 (patch)
treea56727529313eeeac558d29516ead2d4e7b2fc31
parenta1720e4cf7a9b903508fdfe6e8469ea77988f96e (diff)
downloadNetworkManager-3b02c41a54722e7eaa2a73ac4a5ad941d1466041.tar.gz
fixup! core: add manager for default route and support multiple default routes
-rw-r--r--src/devices/nm-device.c170
-rw-r--r--src/nm-default-route-manager.c245
-rw-r--r--src/nm-default-route-manager.h4
-rw-r--r--src/nm-policy.c82
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.");