summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-09-08 13:49:57 +0200
committerThomas Haller <thaller@redhat.com>2017-09-08 13:50:33 +0200
commit4bc231e33abb4f5edb6fc1f42053a06e6e5fd5ec (patch)
tree3e55697d2e25f6b4db765178e11cc0805e4f6a3f
parenta214f398e7b17cacad335f70462a606affc2ad63 (diff)
parent77ec302714795f905301d500b9aab6c88001f32e (diff)
core: merge branch 'th/platform-route-pt4' (part 2)
Drop NMDefaultRouteManager. https://github.com/NetworkManager/NetworkManager/pull/26
-rw-r--r--Makefile.am2
-rw-r--r--src/devices/nm-device.c378
-rw-r--r--src/devices/nm-device.h4
-rw-r--r--src/dns/nm-dns-dnsmasq.c12
-rw-r--r--src/nm-default-route-manager.c1561
-rw-r--r--src/nm-default-route-manager.h64
-rw-r--r--src/nm-dispatcher.c4
-rw-r--r--src/nm-ip4-config.c259
-rw-r--r--src/nm-ip4-config.h27
-rw-r--r--src/nm-ip6-config.c198
-rw-r--r--src/nm-ip6-config.h8
-rw-r--r--src/nm-netns.c10
-rw-r--r--src/nm-netns.h1
-rw-r--r--src/nm-pacrunner-manager.c4
-rw-r--r--src/nm-policy.c202
-rw-r--r--src/nm-types.h1
-rw-r--r--src/platform/nm-platform.c5
-rw-r--r--src/vpn/nm-vpn-connection.c31
18 files changed, 723 insertions, 2048 deletions
diff --git a/Makefile.am b/Makefile.am
index 60b1adf17..2d6e21b92 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1494,8 +1494,6 @@ src_libNetworkManager_la_SOURCES = \
src/nm-dcb.h \
src/nm-netns.c \
src/nm-netns.h \
- src/nm-default-route-manager.c \
- src/nm-default-route-manager.h \
src/nm-dhcp4-config.c \
src/nm-dhcp4-config.h \
src/nm-dhcp6-config.c \
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 364f142a7..aadd2cd6c 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -65,7 +65,6 @@
#include "nm-utils/c-list.h"
#include "dns/nm-dns-manager.h"
#include "nm-core-internal.h"
-#include "nm-default-route-manager.h"
#include "systemd/nm-sd.h"
#include "nm-lldp-listener.h"
#include "nm-audit-manager.h"
@@ -360,14 +359,12 @@ typedef struct _NMDevicePrivate {
NMIP4Config * ext_ip4_config; /* Stuff added outside NM */
NMIP4Config * wwan_ip4_config; /* WWAN configuration */
GSList * vpn4_configs; /* VPNs which use this device */
- struct {
- bool v4_has;
- bool v4_is_assumed;
- bool v6_has;
- bool v6_is_assumed;
- NMPlatformIP4Route v4;
- NMPlatformIP6Route v6;
- } default_route;
+
+ const NMPObject *default_route4;
+ const NMPObject *default_route6;
+ const NMPObject *default_routegw4;
+ const NMPObject *default_routegw6;
+
bool v4_has_shadowed_routes;
const char *ip4_rp_filter;
@@ -1691,62 +1688,33 @@ out:
return nm_utils_ip_route_metric_normalize (addr_family, route_metric);
}
-static void
-_update_default_route (NMDevice *self, int addr_family, gboolean has, gboolean is_assumed)
+const NMPObject *
+nm_device_get_best_default_route (NMDevice *self,
+ int addr_family)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- bool *p_has, *p_is_assumed;
-
- nm_assert (NM_IN_SET (addr_family, 0, AF_INET, AF_INET6));
- if (addr_family == AF_INET) {
- p_has = &priv->default_route.v4_has;
- p_is_assumed = &priv->default_route.v4_is_assumed;
- } else {
- p_has = &priv->default_route.v6_has;
- p_is_assumed = &priv->default_route.v6_is_assumed;
+ /* Prefer the best default-route we have in ipx_config.
+ *
+ * Otherwise, use priv->default_routeX. Usually, we would
+ * expect that if ipx_config has no default route, then
+ * also priv->default_routeX is unset. This is just to cover
+ * a case I cannot imagine now. */
+ switch (addr_family) {
+ case AF_INET:
+ return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL)
+ ?: priv->default_route4;
+ case AF_INET6:
+ return (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL)
+ ?: priv->default_route6;
+ case AF_UNSPEC:
+ return (priv->ip4_config ? nm_ip4_config_best_default_route_get (priv->ip4_config) : NULL)
+ ?: priv->default_route4
+ ?: (priv->ip6_config ? nm_ip6_config_best_default_route_get (priv->ip6_config) : NULL)
+ ?: priv->default_route6;
+ default:
+ g_return_val_if_reached (NULL);
}
-
- if (*p_has == has && *p_is_assumed == is_assumed)
- return;
-
- *p_has = has;
- *p_is_assumed = is_assumed;
-
- if (addr_family == AF_INET)
- nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
- else
- nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
-}
-
-const NMPlatformIP4Route *
-nm_device_get_ip4_default_route (NMDevice *self, gboolean *out_is_assumed)
-{
- NMDevicePrivate *priv;
-
- g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
-
- priv = NM_DEVICE_GET_PRIVATE (self);
-
- if (out_is_assumed)
- *out_is_assumed = priv->default_route.v4_is_assumed;
-
- return priv->default_route.v4_has ? &priv->default_route.v4 : NULL;
-}
-
-const NMPlatformIP6Route *
-nm_device_get_ip6_default_route (NMDevice *self, gboolean *out_is_assumed)
-{
- NMDevicePrivate *priv;
-
- g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
-
- priv = NM_DEVICE_GET_PRIVATE (self);
-
- if (out_is_assumed)
- *out_is_assumed = priv->default_route.v6_is_assumed;
-
- return priv->default_route.v6_has ? &priv->default_route.v6 : NULL;
}
const char *
@@ -1863,7 +1831,7 @@ update_connectivity_state (NMDevice *self, NMConnectivityState state)
/* If the connectivity check is disabled, make an optimistic guess. */
if (state == NM_CONNECTIVITY_UNKNOWN) {
if (priv->state == NM_DEVICE_STATE_ACTIVATED) {
- if (priv->default_route.v4_has || priv->default_route.v6_has)
+ if (nm_device_get_best_default_route (self, AF_UNSPEC))
state = NM_CONNECTIVITY_FULL;
else
state = NM_CONNECTIVITY_LIMITED;
@@ -1883,12 +1851,12 @@ update_connectivity_state (NMDevice *self, NMConnectivityState state)
if ( priv->state == NM_DEVICE_STATE_ACTIVATED
&& !nm_device_sys_iface_state_is_external (self)) {
- if ( priv->default_route.v4_has
+ if ( nm_device_get_best_default_route (self, AF_INET)
&& !ip4_config_merge_and_apply (self, NULL, TRUE))
- _LOGW (LOGD_IP4, "Failed to update IPv4 default route metric");
- if ( priv->default_route.v6_has
+ _LOGW (LOGD_IP4, "Failed to update IPv4 route metric");
+ if ( nm_device_get_best_default_route (self, AF_INET6)
&& !ip6_config_merge_and_apply (self, TRUE))
- _LOGW (LOGD_IP6, "Failed to update IPv6 default route metric");
+ _LOGW (LOGD_IP6, "Failed to update IPv6 route metric");
}
}
}
@@ -2002,7 +1970,7 @@ concheck_periodic_update (NMDevice *self)
gboolean check_enable;
check_enable = (priv->state == NM_DEVICE_STATE_ACTIVATED)
- && (priv->default_route.v4_has || priv->default_route.v6_has);
+ && nm_device_get_best_default_route (self, AF_UNSPEC);
if (check_enable && !priv->concheck_periodic_id) {
/* We just gained a default route. Enable periodic checking. */
@@ -2864,7 +2832,7 @@ ip4_rp_filter_update (NMDevice *self)
const char *ip4_rp_filter;
if ( priv->v4_has_shadowed_routes
- || priv->default_route.v4_has) {
+ || nm_device_get_best_default_route (self, AF_INET)) {
if (nm_device_ipv4_sysctl_get_uint32 (self, "rp_filter", 0) != 1) {
/* Don't touch the rp_filter if it's not strict. */
return;
@@ -3910,15 +3878,6 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config)
if (!unconfigure_ip_config)
return;
- /* Clean up IP configs; this does not actually deconfigure the
- * interface, it just clears the configuration to which policy
- * is reacting via NM_DEVICE_IP4_CONFIG_CHANGED/NM_DEVICE_IP6_CONFIG_CHANGED
- * signal. As NMPolicy registered the NMIPxConfig instances in NMDnsManager,
- * these would be leaked otherwise. */
- _update_default_route (self, AF_INET, priv->default_route.v4_has, TRUE);
- _update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE);
- _update_default_route (self, AF_INET, FALSE, TRUE);
- _update_default_route (self, AF_INET6, FALSE, TRUE);
nm_device_set_ip4_config (self, NULL, 0, FALSE);
nm_device_set_ip6_config (self, NULL, FALSE);
}
@@ -5516,49 +5475,6 @@ ipv4ll_start (NMDevice *self)
/*****************************************************************************/
-static gboolean
-_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route)
-{
- int ifindex = nm_device_get_ip_ifindex (self);
- const NMDedupMultiHeadEntry *pl_head_entry;
- NMDedupMultiIter iter;
- const NMPObject *plobj = NULL;
- const NMPlatformIPRoute *route = NULL;
- guint32 route_metric = G_MAXUINT32;
-
- pl_head_entry = nm_platform_lookup_route_default (nm_device_get_platform (self),
- addr_family == AF_INET
- ? NMP_OBJECT_TYPE_IP4_ROUTE
- : NMP_OBJECT_TYPE_IP6_ROUTE);
- nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
- guint32 m;
- const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
-
- if ( r->ifindex != ifindex
- || r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
- || r->table_coerced)
- continue;
-
- /* if there are several default routes, find the one with the best metric */
- m = nm_utils_ip_route_metric_normalize (addr_family, r->metric);
- if (!route || m < route_metric) {
- route = NMP_OBJECT_CAST_IP_ROUTE (plobj);
- route_metric = m;
- }
- }
-
- if (route) {
- if (addr_family == AF_INET)
- *((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
- else
- *((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
- return TRUE;
- }
- return FALSE;
-}
-
-/*****************************************************************************/
-
static void
ensure_con_ip4_config (NMDevice *self)
{
@@ -5648,14 +5564,13 @@ 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);
guint32 gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
- gboolean auto_method = FALSE;
GSList *iter;
+ NMPlatformIP4Route default_route;
/* Merge all the configs into the composite config */
if (config) {
@@ -5671,10 +5586,6 @@ ip4_config_merge_and_apply (NMDevice *self,
if (s_ip4) {
ignore_auto_routes = nm_setting_ip_config_get_ignore_auto_routes (s_ip4);
ignore_auto_dns = nm_setting_ip_config_get_ignore_auto_dns (s_ip4);
-
- if (nm_streq0 (nm_setting_ip_config_get_method (s_ip4),
- NM_SETTING_IP4_CONFIG_METHOD_AUTO))
- auto_method = TRUE;
}
}
@@ -5718,40 +5629,17 @@ ip4_config_merge_and_apply (NMDevice *self,
if (priv->con_ip4_config)
nm_ip4_config_merge (composite, priv->con_ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
- /* 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;
+ /* Add the default route... */
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
- /* a generated-assumed connection detects the default route from the platform,
- * but if the IP method is automatic we need to update the default route to
- * maintain connectivity.
- */
- if (nm_device_sys_iface_state_is_external (self) && !auto_method)
+ /* for external connections, we always pickup whatever is configured. */
+ if (nm_device_sys_iface_state_is_external (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.
- */
-
connection_has_default_route
= nm_utils_connection_has_default_route (connection, AF_INET, &connection_is_never_default);
@@ -5763,9 +5651,8 @@ ip4_config_merge_and_apply (NMDevice *self,
goto END_ADD_DEFAULT_ROUTE;
}
- /* we are about to commit (for a non-assumed connection). Enforce whatever we have
- * configured. */
- priv->default_route.v4_is_assumed = FALSE;
+ nm_clear_nmp_object (&priv->default_route4);
+ nm_clear_nmp_object (&priv->default_routegw4);
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
@@ -5780,38 +5667,26 @@ ip4_config_merge_and_apply (NMDevice *self,
&& nm_device_get_device_type (self) != NM_DEVICE_TYPE_MODEM)
goto END_ADD_DEFAULT_ROUTE;
- has_direct_route = ( gateway == 0
- || nm_ip4_config_destination_is_direct (composite, gateway, 32)
- || 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.rt_source = NM_IP_CONFIG_SOURCE_USER;
- priv->default_route.v4.gateway = gateway;
- priv->default_route.v4.metric = route_metric_with_penalty (self, default_route_metric);
- priv->default_route.v4.mss = nm_ip4_config_get_mss (composite);
-
- if (!has_direct_route) {
- NMPlatformIP4Route r = priv->default_route.v4;
-
+ memset (&default_route, 0, sizeof (default_route));
+ default_route.rt_source = NM_IP_CONFIG_SOURCE_USER;
+ default_route.gateway = gateway;
+ default_route.metric = route_metric_with_penalty (self, default_route_metric);
+ default_route.mss = nm_ip4_config_get_mss (composite);
+ nm_clear_nmp_object (&priv->default_route4);
+ nm_ip4_config_add_route (composite, &default_route, &priv->default_route4);
+
+ if (!( gateway == 0
+ || nm_ip4_config_destination_is_direct (composite, gateway, 32)
+ || nm_ip4_config_get_direct_route_for_host (composite, gateway))) {
/* add a direct route to the gateway */
- r.network = gateway;
- r.plen = 32;
- r.gateway = 0;
- nm_ip4_config_add_route (composite, &r, NULL);
+ default_route.network = gateway;
+ default_route.plen = 32;
+ default_route.gateway = 0;
+ nm_clear_nmp_object (&priv->default_routegw4);
+ nm_ip4_config_add_route (composite, &default_route, &priv->default_routegw4);
}
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);
- }
-
if (commit) {
if (NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit)
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
@@ -6369,14 +6244,13 @@ ip6_config_merge_and_apply (NMDevice *self,
NMConnection *connection;
gboolean success;
NMIP6Config *composite;
- gboolean has_direct_route;
const struct in6_addr *gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
- gboolean auto_method = FALSE;
const char *token = NULL;
GSList *iter;
+ NMPlatformIP6Route default_route;
/* Apply ignore-auto-routes and ignore-auto-dns settings */
connection = nm_device_get_applied_connection (self);
@@ -6391,11 +6265,6 @@ ip6_config_merge_and_apply (NMDevice *self,
if (nm_setting_ip6_config_get_addr_gen_mode (ip6) == NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64)
token = nm_setting_ip6_config_get_token (ip6);
-
- if (NM_IN_STRSET (nm_setting_ip_config_get_method (s_ip6),
- NM_SETTING_IP6_CONFIG_METHOD_AUTO,
- NM_SETTING_IP6_CONFIG_METHOD_DHCP))
- auto_method = TRUE;
}
}
@@ -6453,40 +6322,17 @@ ip6_config_merge_and_apply (NMDevice *self,
if (priv->con_ip6_config)
nm_ip6_config_merge (composite, priv->con_ip6_config, NM_IP_CONFIG_MERGE_DEFAULT);
- /* 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;
+ /* Add the default route... */
if (!commit) {
/* during a non-commit event, we always pickup whatever is configured. */
goto END_ADD_DEFAULT_ROUTE;
}
- /* a generated-assumed connection detects the default route from the platform,
- * but if the IP method is automatic we need to update the default route to
- * maintain connectivity.
- */
- if (nm_device_sys_iface_state_is_external (self) && !auto_method)
+ /* for external connections, we always pickup whatever is configured. */
+ if (nm_device_sys_iface_state_is_external (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.
- */
-
connection_has_default_route
= nm_utils_connection_has_default_route (connection, AF_INET6, &connection_is_never_default);
@@ -6498,9 +6344,8 @@ ip6_config_merge_and_apply (NMDevice *self,
goto END_ADD_DEFAULT_ROUTE;
}
- /* we are about to commit (for a non-assumed connection). Enforce whatever we have
- * configured. */
- priv->default_route.v6_is_assumed = FALSE;
+ nm_clear_nmp_object (&priv->default_route6);
+ nm_clear_nmp_object (&priv->default_routegw6);
if (!connection_has_default_route)
goto END_ADD_DEFAULT_ROUTE;
@@ -6514,40 +6359,25 @@ ip6_config_merge_and_apply (NMDevice *self,
if (!gateway)
goto END_ADD_DEFAULT_ROUTE;
+ memset (&default_route, 0, sizeof (default_route));
+ default_route.rt_source = NM_IP_CONFIG_SOURCE_USER;
+ default_route.gateway = *gateway;
+ default_route.metric = route_metric_with_penalty (self,
+ nm_device_get_ip6_route_metric (self));
+ default_route.mss = nm_ip6_config_get_mss (composite);
+ nm_clear_nmp_object (&priv->default_route6);
+ nm_ip6_config_add_route (composite, &default_route, &priv->default_route6);
- has_direct_route = nm_ip6_config_get_direct_route_for_host (composite, gateway) != NULL;
-
-
-
- priv->default_route.v6_has = TRUE;
- memset (&priv->default_route.v6, 0, sizeof (priv->default_route.v6));
- priv->default_route.v6.rt_source = NM_IP_CONFIG_SOURCE_USER;
- priv->default_route.v6.gateway = *gateway;
- priv->default_route.v6.metric = route_metric_with_penalty (self,
- 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 (!nm_ip6_config_get_direct_route_for_host (composite, gateway)) {
/* add a direct route to the gateway */
- r.network = *gateway;
- r.plen = 128;
- r.gateway = in6addr_any;
- nm_ip6_config_add_route (composite, &r, NULL);
+ default_route.network = *gateway;
+ default_route.plen = 128;
+ default_route.gateway = in6addr_any;
+ nm_clear_nmp_object (&priv->default_routegw6);
+ nm_ip6_config_add_route (composite, &default_route, &priv->default_routegw6);
}
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);
- }
-
/* Allow setting MTU etc */
if (commit) {
NMUtilsIPv6IfaceId iid;
@@ -8914,6 +8744,8 @@ _cleanup_ip4_pre (NMDevice *self, CleanupType cleanup_type)
_LOGD (LOGD_DEVICE, "clearing queued IP4 config change");
priv->queued_ip4_config_pending = FALSE;
+ nm_clear_nmp_object (&priv->default_route4);
+ nm_clear_nmp_object (&priv->default_routegw4);
dhcp4_cleanup (self, cleanup_type, FALSE);
arp_cleanup (self);
dnsmasq_cleanup (self);
@@ -8931,6 +8763,8 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
_LOGD (LOGD_DEVICE, "clearing queued IP6 config change");
priv->queued_ip6_config_pending = FALSE;
+ nm_clear_nmp_object (&priv->default_route6);
+ nm_clear_nmp_object (&priv->default_routegw6);
g_clear_object (&priv->dad6_ip6_config);
dhcp6_cleanup (self, cleanup_type, FALSE);
linklocal6_cleanup (self);
@@ -9887,7 +9721,6 @@ nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *old_config = NULL;
gboolean has_changes = FALSE;
gboolean success = TRUE;
- gboolean def_route_changed;
int ip_ifindex = 0;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
@@ -9940,7 +9773,6 @@ nm_device_set_ip4_config (NMDevice *self,
g_clear_object (&priv->dev_ip4_config);
}
- def_route_changed = nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
concheck_periodic_update (self);
if (!nm_device_sys_iface_state_is_external_or_assume (self))
@@ -9974,9 +9806,6 @@ nm_device_set_ip4_config (NMDevice *self,
}
nm_device_queue_recheck_assume (self);
- } else if (def_route_changed) {
- _LOGD (LOGD_IP4, "ip4-config: default route changed");
- g_signal_emit (self, signals[IP4_CONFIG_CHANGED], 0, priv->ip4_config, priv->ip4_config);
}
return success;
@@ -10059,7 +9888,6 @@ nm_device_set_ip6_config (NMDevice *self,
NMIP6Config *old_config = NULL;
gboolean has_changes = FALSE;
gboolean success = TRUE;
- gboolean def_route_changed;
int ip_ifindex = 0;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
@@ -10110,8 +9938,6 @@ nm_device_set_ip6_config (NMDevice *self,
nm_exported_object_get_path (NM_EXPORTED_OBJECT (old_config)));
}
- def_route_changed = nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
-
if (has_changes) {
NMSettingsConnection *settings_connection;
@@ -10141,9 +9967,6 @@ nm_device_set_ip6_config (NMDevice *self,
if (priv->ndisc)
ndisc_set_router_config (priv->ndisc, self);
- } else if (def_route_changed) {
- _LOGD (LOGD_IP6, "ip6-config: default route changed");
- g_signal_emit (self, signals[IP6_CONFIG_CHANGED], 0, priv->ip6_config, priv->ip6_config);
}
return success;
@@ -10798,6 +10621,12 @@ update_ip4_config (NMDevice *self, gboolean initial)
nm_ip4_config_intersect (priv->wwan_ip4_config, priv->ext_ip4_config);
for (iter = priv->vpn4_configs; iter; iter = iter->next)
nm_ip4_config_intersect (iter->data, priv->ext_ip4_config);
+ if ( priv->default_route4
+ && !nm_ip4_config_nmpobj_lookup (priv->ext_ip4_config, priv->default_route4))
+ nm_clear_nmp_object (&priv->default_route4);
+ if ( priv->default_routegw4
+ && !nm_ip4_config_nmpobj_lookup (priv->ext_ip4_config, priv->default_routegw4))
+ nm_clear_nmp_object (&priv->default_routegw4);
/* Remove parts from ext_ip4_config to only contain the information that
* was configured externally -- we already have the same configuration from
@@ -10810,6 +10639,10 @@ update_ip4_config (NMDevice *self, gboolean initial)
nm_ip4_config_subtract (priv->ext_ip4_config, priv->wwan_ip4_config);
for (iter = priv->vpn4_configs; iter; iter = iter->next)
nm_ip4_config_subtract (priv->ext_ip4_config, iter->data);
+ if (priv->default_route4)
+ nm_ip4_config_nmpobj_remove (priv->ext_ip4_config, priv->default_route4);
+ if (priv->default_routegw4)
+ nm_ip4_config_nmpobj_remove (priv->ext_ip4_config, priv->default_routegw4);
ip4_config_merge_and_apply (self, NULL, FALSE);
}
@@ -10870,6 +10703,12 @@ update_ip6_config (NMDevice *self, gboolean initial)
nm_ip6_config_intersect (priv->wwan_ip6_config, priv->ext_ip6_config);
for (iter = priv->vpn6_configs; iter; iter = iter->next)
nm_ip6_config_intersect (iter->data, priv->ext_ip6_config);
+ if ( priv->default_route6
+ && !nm_ip6_config_nmpobj_lookup (priv->ext_ip6_config, priv->default_route6))
+ nm_clear_nmp_object (&priv->default_route6);
+ if ( priv->default_routegw6
+ && !nm_ip6_config_nmpobj_lookup (priv->ext_ip6_config, priv->default_routegw6))
+ nm_clear_nmp_object (&priv->default_routegw6);
/* Remove parts from ext_ip6_config to only contain the information that
* was configured externally -- we already have the same configuration from
@@ -10884,6 +10723,10 @@ update_ip6_config (NMDevice *self, gboolean initial)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->wwan_ip6_config);
for (iter = priv->vpn6_configs; iter; iter = iter->next)
nm_ip6_config_subtract (priv->ext_ip6_config, iter->data);
+ if (priv->default_route6)
+ nm_ip6_config_nmpobj_remove (priv->ext_ip6_config, priv->default_route6);
+ if (priv->default_routegw6)
+ nm_ip6_config_nmpobj_remove (priv->ext_ip6_config, priv->default_routegw6);
ip6_config_merge_and_apply (self, FALSE);
}
@@ -12118,16 +11961,6 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
- _update_default_route (self, AF_INET, FALSE, FALSE);
- _update_default_route (self, AF_INET6, FALSE, FALSE);
- } else {
- _update_default_route (self, AF_INET, priv->default_route.v4_has, TRUE);
- _update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE);
- }
- _update_default_route (self, AF_INET, FALSE, TRUE);
- _update_default_route (self, AF_INET6, FALSE, TRUE);
-
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
@@ -12138,6 +11971,10 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
*/
nm_device_set_ip4_config (self, NULL, 0, TRUE);
nm_device_set_ip6_config (self, NULL, TRUE);
+ nm_clear_nmp_object (&priv->default_route4);
+ nm_clear_nmp_object (&priv->default_route6);
+ nm_clear_nmp_object (&priv->default_routegw4);
+ nm_clear_nmp_object (&priv->default_routegw6);
g_clear_object (&priv->proxy_config);
g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->dev_ip4_config);
@@ -13819,9 +13656,6 @@ nm_device_init (NMDevice *self)
priv->ip6_saved_properties = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
priv->sys_iface_state = NM_DEVICE_SYS_IFACE_STATE_EXTERNAL;
- priv->default_route.v4_is_assumed = TRUE;
- priv->default_route.v6_is_assumed = TRUE;
-
priv->v4_commit_first_time = TRUE;
priv->v6_commit_first_time = TRUE;
}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index f46a64ca2..811fc258e 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -710,8 +710,8 @@ gboolean nm_device_owns_iface (NMDevice *device, const char *iface);
NMConnection *nm_device_new_default_connection (NMDevice *self);
-const NMPlatformIP4Route *nm_device_get_ip4_default_route (NMDevice *self, gboolean *out_is_assumed);
-const NMPlatformIP6Route *nm_device_get_ip6_default_route (NMDevice *self, gboolean *out_is_assumed);
+const NMPObject *nm_device_get_best_default_route (NMDevice *self,
+ int addr_family);
void nm_device_spawn_iface_helper (NMDevice *self);
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index cb311dffd..3ec1fd2de 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -91,8 +91,10 @@ get_ip4_rdns_domains (NMIP4Config *ip4)
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address)
nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
- nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route)
- nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
+ if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
+ }
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
@@ -119,8 +121,10 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
- nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route)
- nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
+ if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
+ }
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
deleted file mode 100644
index dc8f83b4a..000000000
--- a/src/nm-default-route-manager.c
+++ /dev/null
@@ -1,1561 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-
-#include "nm-default.h"
-
-#include "nm-default-route-manager.h"
-
-#include <string.h>
-
-#include "devices/nm-device.h"
-#include "vpn/nm-vpn-connection.h"
-#include "platform/nm-platform.h"
-#include "platform/nm-platform-utils.h"
-#include "platform/nmp-object.h"
-#include "nm-manager.h"
-#include "nm-ip4-config.h"
-#include "nm-ip6-config.h"
-#include "nm-act-request.h"
-
-/*****************************************************************************/
-
-NM_GOBJECT_PROPERTIES_DEFINE_BASE (
- PROP_LOG_WITH_PTR,
- PROP_PLATFORM,
-);
-
-typedef struct {
- GPtrArray *entries_ip4;
- GPtrArray *entries_ip6;
-
- NMPlatform *platform;
-
- struct {
- guint guard;
- guint backoff_wait_time_ms;
- guint idle_handle;
- gboolean has_v4_changes;
- gboolean has_v6_changes;
- } resync;
-
- /* During disposing, we unref the sources of all entries. This happens usually
- * during shutdown, which might call the final deletion of the object. That
- * again might cause calls back into NMDefaultRouteManager, which finds dangling
- * pointers.
- * Guard every publicly accessible function to return early if the instance
- * is already disposing. */
- bool disposed;
-
- bool log_with_ptr;
-} NMDefaultRouteManagerPrivate;
-
-struct _NMDefaultRouteManager {
- GObject parent;
- NMDefaultRouteManagerPrivate _priv;
-};
-
-struct _NMDefaultRouteManagerClass {
- GObjectClass parent;
-};
-
-G_DEFINE_TYPE (NMDefaultRouteManager, nm_default_route_manager, G_TYPE_OBJECT)
-
-#define NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDefaultRouteManager, NM_IS_DEFAULT_ROUTE_MANAGER)
-
-/*****************************************************************************/
-
-#define _NMLOG_PREFIX_NAME "default-route"
-#undef _NMLOG_ENABLED
-#define _NMLOG_ENABLED(level, addr_family) \
- ({ \
- const int __addr_family = (addr_family); \
- const NMLogLevel __level = (level); \
- const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
- \
- nm_logging_enabled (__level, __domain); \
- })
-#define _NMLOG(level, addr_family, ...) \
- G_STMT_START { \
- const int __addr_family = (addr_family); \
- const NMLogLevel __level = (level); \
- const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
- \
- if (nm_logging_enabled (__level, __domain)) { \
- char __prefix_buf[100]; \
- \
- _nm_log (__level, __domain, 0, NULL, NULL, \
- "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr \
- ? nm_sprintf_buf (__prefix_buf, "%s%c[%p]", \
- _NMLOG2_PREFIX_NAME, \
- __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'), \
- self) \
- : _NMLOG2_PREFIX_NAME \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } G_STMT_END
-
-#define _NMLOG2_PREFIX_NAME _NMLOG_PREFIX_NAME
-#undef _NMLOG2_ENABLED
-#define _NMLOG2_ENABLED _NMLOG_ENABLED
-#define _NMLOG2(level, vtable, entry_idx, entry, ...) \
- G_STMT_START { \
- const int __addr_family = (vtable)->vt->addr_family; \
- const NMLogLevel __level = (level); \
- const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \
- \
- if (nm_logging_enabled (__level, __domain)) { \
- char __prefix_buf[100]; \
- guint __entry_idx = (entry_idx); \
- const Entry *const __entry = (entry); \
- \
- _nm_log (__level, __domain, 0, NULL, NULL, \
- "%s: entry[%u/%s:%p:%s:%chas:%csync]: "_NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
- NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr \
- ? nm_sprintf_buf (__prefix_buf, "%s%c[%p]", \
- _NMLOG2_PREFIX_NAME, \
- __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'), \
- self) \
- : _NMLOG2_PREFIX_NAME, \
- __entry_idx, \
- NM_IS_DEVICE (__entry->source.pointer) ? "dev" : "vpn", \
- __entry->source.pointer, \
- NM_IS_DEVICE (__entry->source.pointer) ? nm_device_get_iface (__entry->source.device) : nm_active_connection_get_settings_connection_id (NM_ACTIVE_CONNECTION (__entry->source.vpn)), \
- (__entry->never_default ? '-' : '+'), \
- (__entry->synced ? '+' : '-') \
- _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
- } \
- } G_STMT_END
-
-/*****************************************************************************/
-
-static void _resync_idle_cancel (NMDefaultRouteManager *self);
-
-/*****************************************************************************/
-
-typedef struct {
- union {
- void *pointer;
- GObject *object;
- NMDevice *device;
- NMVpnConnection *vpn;
- } source;
- NMPlatformIPXRoute route;
-
- /* Whether the route is synced to platform and has a default route.
- *
- * ( synced && !never_default): the interface gets a default route that
- * is enforced and managed by NMDefaultRouteManager.
- *
- * (!synced && !never_default): the interface has this route, but it is assumed.
- * Assumed interfaces are those that have no tracked entry or that only have
- * (!synced && !never_default) entries. NMDefaultRouteManager will not touch
- * default routes on these interfaces.
- * This combination makes only sense for device sources.
- * They are tracked so that assumed devices can also be the best device.
- *
- * ( synced && never_default): entries of this kind are a placeholder
- * to indicate that the ifindex is managed but has no default-route.
- * Missing entries also indicate that a certain ifindex has no default-route.
- * The difference is that missing entries are considered assumed while on
- * (synced && never_default) entries the absence of the default route
- * is enforced. NMDefaultRouteManager will actively remove any default
- * route on such ifindexes.
- * Also, for VPN sources in addition we track them so that a never-default
- * VPN connection can be chosen by get_best_config() to receive the DNS configuration.
- *
- * (!synced && never_default): this combination makes no sense.
- */
- gboolean synced;
- gboolean never_default;
-
- guint32 effective_metric;
-} Entry;
-
-typedef struct {
- const NMPlatformVTableRoute *vt;
- GPtrArray *(*get_entries) (NMDefaultRouteManagerPrivate *priv);
-} VTableIP;
-
-static const VTableIP vtable_ip4, vtable_ip6;
-
-static gboolean
-_vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Entry *entry)
-{
- guint i;
- NMPlatformIPXRoute route = entry->route;
-
- if (!routes)
- return FALSE;
-
- route.rx.metric = entry->effective_metric;
-
- if (vtable->vt->is_ip4) {
- for (i = 0; i < routes->len; i++) {
- const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (routes->pdata[i]);
-
- route.rx.rt_source = r->rt_source;
- if (nm_platform_ip4_route_cmp_full (r, &route.r4) == 0)
- return TRUE;
- }
- } else {
- for (i = 0; i < routes->len; i++) {
- const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (routes->pdata[i]);
-
- route.rx.rt_source = r->rt_source;
- if (nm_platform_ip6_route_cmp_full (r, &route.r6) == 0)
- return TRUE;
- }
- }
- return FALSE;
-}
-
-static void
-_entry_free (Entry *entry)
-{
- if (entry) {
- g_object_unref (entry->source.object);
- g_slice_free (Entry, entry);
- }
-}
-
-static Entry *
-_entry_find_by_source (GPtrArray *entries, gpointer source, guint *out_idx)
-{
- guint i;
-
- for (i = 0; i < entries->len; i++) {
- Entry *e = g_ptr_array_index (entries, i);
-
- if (e->source.pointer == source) {
- if (out_idx)
- *out_idx = i;
- return e;
- }
- }
-
- if (out_idx)
- *out_idx = G_MAXUINT;
- return NULL;
-}
-
-static gboolean
-_platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, guint32 metric)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- GPtrArray *entries = vtable->get_entries (priv);
- char buf1[sizeof (_nm_utils_to_string_buffer)];
- char buf2[sizeof (_nm_utils_to_string_buffer)];
- guint i;
- Entry *entry_unsynced = NULL;
- Entry *entry = NULL;
- gboolean success;
-
- /* Find the entries for the given metric.
- * The effective metric for synced entries is chosen in a way that it
- * is unique (except for G_MAXUINT32, where a clash is not solvable). */
- for (i = 0; i < entries->len; i++) {
- Entry *e = g_ptr_array_index (entries, i);
-
- if (e->never_default)
- continue;
-
- if (e->effective_metric != metric)
- continue;
-
- if (e->synced) {
- g_assert (!entry || metric == G_MAXUINT32);
- if (!entry)
- entry = e;
- } else
- entry_unsynced = e;
- }
-
- /* We don't expect to have an unsynced *and* a synced entry for the same metric.
- * Unless, (a) their metric is G_MAXUINT32, in which case we could not find an unused effective metric,
- * or (b) if we have an unsynced and a synced entry for the same ifindex.
- * The latter case happens for example when activating an openvpn connection (synced) and
- * assuming the corresponding tun0 interface (unsynced). */
- g_assert (!entry || !entry_unsynced || (entry->route.rx.ifindex == entry_unsynced->route.rx.ifindex) || metric == G_MAXUINT32);
-
- /* we only add the route, if we have an (to be synced) entry for it. */
- if (!entry)
- return FALSE;
-
- if (vtable->vt->is_ip4) {
- NMPObject obj;
- NMPlatformIP4Route *rt;
- const NMPObject *plobj;
-
- nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP4_ROUTE, (const NMPlatformObject *) &entry->route.r4);
- rt = NMP_OBJECT_CAST_IP4_ROUTE (&obj);
- rt->network = 0;
- rt->plen = 0;
- rt->metric = entry->effective_metric;
-
- nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) rt);
- plobj = nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (priv->platform,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- &obj));
- if ( plobj
- && nm_platform_ip4_route_cmp (rt,
- NMP_OBJECT_CAST_IP4_ROUTE (plobj),
- NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) == 0) {
- _LOGt (AF_INET, "already exists: %s",
- nm_platform_ip4_route_to_string (rt, NULL, 0));
- return FALSE;
- }
-
- if (plobj) {
- _LOGt (AF_INET, "update platform route: %s; with route: %s",
- nm_platform_ip4_route_to_string (NMP_OBJECT_CAST_IP4_ROUTE (plobj), buf1, sizeof (buf1)),
- nm_platform_ip4_route_to_string (rt, buf2, sizeof (buf2)));
- }
-
- success = (nm_platform_ip4_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, rt) == NM_PLATFORM_ERROR_SUCCESS);
- } else {
- NMPObject obj;
- NMPlatformIP6Route *rt;
- const NMPObject *plobj;
-
- nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, (const NMPlatformObject *) &entry->route.r6);
- rt = NMP_OBJECT_CAST_IP6_ROUTE (&obj);
- rt->network = in6addr_any;
- rt->plen = 0;
- rt->metric = entry->effective_metric;
-
- nm_platform_ip_route_normalize (AF_INET6, (NMPlatformIPRoute *) rt);
- plobj = nm_dedup_multi_entry_get_obj (nm_platform_lookup_entry (priv->platform,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- &obj));
- if ( plobj
- && nm_platform_ip6_route_cmp (rt,
- NMP_OBJECT_CAST_IP6_ROUTE (plobj),
- NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) == 0) {
- _LOGt (AF_INET, "already exists: %s",
- nm_platform_ip6_route_to_string (rt, NULL, 0));
- return FALSE;
- }
-
- if (plobj) {
- _LOGt (AF_INET, "update platform route: %s; with route: %s",
- nm_platform_ip6_route_to_string (NMP_OBJECT_CAST_IP6_ROUTE (plobj), buf1, sizeof (buf1)),
- nm_platform_ip6_route_to_string (rt, buf2, sizeof (buf2)));
- }
-
- success = (nm_platform_ip6_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, rt) == NM_PLATFORM_ERROR_SUCCESS);
- }
-
- if (!success) {
- _LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric);
- }
- return TRUE;
-}
-
-static gboolean
-_platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, int ifindex_to_flush)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- GPtrArray *entries = vtable->get_entries (priv);
- gs_unref_ptrarray GPtrArray *routes = NULL;
- guint i, j;
- gboolean changed = FALSE;
-
- /* prune all other default routes from this device. */
-
- routes = nm_platform_lookup_route_default_clone (priv->platform,
- vtable->vt->obj_type,
- nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
- NULL);
- if (!routes)
- return FALSE;
-
- for (i = 0; i < routes->len; i++) {
- const NMPlatformIPRoute *route;
- gboolean has_ifindex_synced = FALSE;
- Entry *entry = NULL;
-
- route = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
-
- /* look at all entries and see if the route for this ifindex pair is
- * a known entry. */
- for (j = 0; j < entries->len; j++) {
- Entry *e = g_ptr_array_index (entries, j);
-
- if ( e->route.rx.ifindex == route->ifindex
- && e->synced) {
- has_ifindex_synced = TRUE;
- if ( !e->never_default
- && e->effective_metric == route->metric)
- entry = e;
- }
- }
-
- /* we only delete the route if we don't have a matching entry,
- * and there is at least one entry that references this ifindex
- * (indicating that the ifindex is managed by us -- not assumed).
- *
- * Otherwise, don't delete the route because it's configured
- * externally (and will be assumed -- or already is assumed).
- */
- if ( !entry
- && (has_ifindex_synced || ifindex_to_flush == route->ifindex)) {
- nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (route));
- changed = TRUE;
- }
- }
- return changed;
-}
-
-static int
-_sort_entries_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
-{
- guint32 m_a, m_b;
- const Entry *e_a = *((const Entry **) a);
- const Entry *e_b = *((const Entry **) b);
-
- /* when comparing routes, we consider the (original) metric. */
- m_a = e_a->route.rx.metric;
- m_b = e_b->route.rx.metric;
-
- /* we normalize route.metric already in _ipx_update_default_route().
- * so we can just compare the metrics numerically */
-
- if (m_a != m_b)
- return (m_a < m_b) ? -1 : 1;
-
- /* If the metrics are equal, we prefer the one that is !never_default */
- if (!!e_a->never_default != !!e_b->never_default)
- return e_a->never_default ? 1 : -1;
-
- /* If the metrics are equal, we prefer the one that is assumed (!synced).
- * Entries that we sync, can be modified so that only the best
- * entry has a (deterministically) lowest metric.
- * With assumed devices we cannot increase/change the metric.
- * For example: two devices, both metric 0. One is assumed the other is
- * synced.
- * If we would choose the synced entry as best, we cannot
- * increase the metric of the assumed one and we would have non-determinism.
- * If we instead prefer the assumed device, we can increase the metric
- * of the synced device and the assumed device is (deterministically)
- * prefered.
- * If both devices are assumed, we also have non-determinism, but also
- * we don't reorder either.
- */
- if (!!e_a->synced != !!e_b->synced)
- return e_a->synced ? 1 : -1;
-
- /* otherwise, do not reorder */
- return 0;
-}
-
-static GHashTable *
-_get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, const GPtrArray *routes)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- GPtrArray *entries;
- guint i, j;
- GHashTable *result;
-
- /* create a list of all metrics that are currently assigned on an interface
- * that is *not* already covered by one of our synced entries.
- * IOW, returns the metrics that are in use by assumed interfaces
- * that we want to preserve. */
-
- entries = vtable->get_entries (priv);
-
- result = g_hash_table_new (NULL, NULL);
-
- if (routes) {
- for (i = 0; i < routes->len; i++) {
- gboolean ifindex_has_synced_entry = FALSE;
- const NMPlatformIPRoute *route;
-
- route = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
-
- for (j = 0; j < entries->len; j++) {
- Entry *e = g_ptr_array_index (entries, j);
-
- if ( e->synced
- && e->route.rx.ifindex == route->ifindex) {
- ifindex_has_synced_entry = TRUE;
- break;
- }
- }
-
- if (!ifindex_has_synced_entry)
- g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric)));
- }
- }
-
- /* also add all non-synced metrics from our entries list. We might have there some metrics that
- * we track as non-synced but that are no longer part of platform routes. Anyway, for now
- * we still want to treat them as assumed. */
- for (i = 0; i < entries->len; i++) {
- gboolean ifindex_has_synced_entry = FALSE;
- Entry *e_i = g_ptr_array_index (entries, i);
-
- if (e_i->synced)
- continue;
-
- for (j = 0; j < entries->len; j++) {
- Entry *e_j = g_ptr_array_index (entries, j);
-
- if ( j != i
- && (e_j->synced && e_j->route.rx.ifindex == e_i->route.rx.ifindex)) {
- ifindex_has_synced_entry = TRUE;
- break;
- }
- }
-
- if (!ifindex_has_synced_entry)
- g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (e_i->route.rx.metric)));
- }
-
- return result;
-}
-
-static gboolean
-_resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *changed_entry, const Entry *old_entry, gboolean external_change)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- Entry *entry;
- guint i, j;
- gint64 last_metric = -1;
- guint32 expected_metric;
- GPtrArray *entries;
- GArray *changed_metrics = g_array_new (FALSE, FALSE, sizeof (guint32));
- GHashTable *assumed_metrics;
- gs_unref_ptrarray GPtrArray *routes = NULL;
- gboolean changed = FALSE;
- int ifindex_to_flush = 0;
-
- g_assert (priv->resync.guard == 0);
- priv->resync.guard++;
-
- if (!external_change) {
- if (vtable->vt->is_ip4)
- priv->resync.has_v4_changes = FALSE;
- else
- priv->resync.has_v6_changes = FALSE;
- if (!priv->resync.has_v4_changes && !priv->resync.has_v6_changes)
- _resync_idle_cancel (self);
- }
-
- entries = vtable->get_entries (priv);
-
- routes = nm_platform_lookup_route_default_clone (priv->platform,
- vtable->vt->obj_type,
- nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
- NULL);
-
- assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes);
-
- if (old_entry && old_entry->synced && !old_entry->never_default) {
- /* The old version obviously changed. */
- g_array_append_val (changed_metrics, old_entry->effective_metric);
- }
-
- /* first iterate over all entries and adjust the effective metrics. */
- for (i = 0; i < entries->len; i++) {
- entry = g_ptr_array_index (entries, i);
-
- if (entry->never_default)
- continue;
-
- if (!entry->synced) {
- gboolean has_synced_entry = FALSE;
-
- /* A non synced entry is completely ignored, if we have
- * a synced entry for the same if index.
- * Otherwise the metric of the entry is still remembered as
- * last_metric to avoid reusing it. */
- for (j = 0; j < entries->len; j++) {
- const Entry *e = g_ptr_array_index (entries, j);
-
- if ( e->synced
- && e->route.rx.ifindex == entry->route.rx.ifindex) {
- has_synced_entry = TRUE;
- break;
- }
- }
- if (!has_synced_entry)
- last_metric = MAX (last_metric, (gint64) entry->effective_metric);
- continue;
- }
-
- expected_metric = entry->route.rx.metric;
- if ((gint64) expected_metric <= last_metric)
- expected_metric = last_metric == G_MAXUINT32 ? G_MAXUINT32 : last_metric + 1;
-
- while ( expected_metric < G_MAXUINT32
- && g_hash_table_contains (assumed_metrics, GUINT_TO_POINTER (expected_metric))) {
- gboolean has_metric_for_ifindex = FALSE;
-
- /* Check if there are assumed devices that have default routes with this metric.
- * If there are any, we have to pick another effective_metric. */
-
- /* However, if there is a matching route (ifindex+metric) for our current entry, we are done. */
- if (routes) {
- for (j = 0; j < routes->len; j++) {
- const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
-
- if ( r->metric == expected_metric
- && r->ifindex == entry->route.rx.ifindex) {
- has_metric_for_ifindex = TRUE;
- break;
- }
- }
- }
- if (has_metric_for_ifindex)
- break;
- expected_metric++;
- }
-
- if (changed_entry == entry) {
- /* for the changed entry, the previous metric was either old_entry->effective_metric,
- * or none. Hence, we only have to remember what is going to change. */
- g_array_append_val (changed_metrics, expected_metric);
- if (!old_entry) {
- _LOG2D (vtable, i, entry, "sync:add %s (%u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric);
- } else if (old_entry != changed_entry) {
- _LOG2D (vtable, i, entry, "sync:update %s (%u -> %u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) old_entry->effective_metric,
- (guint) expected_metric);
- } else {
- _LOG2D (vtable, i, entry, "sync:resync %s (%u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric);
- }
- } else if (entry->effective_metric != expected_metric) {
- g_array_append_val (changed_metrics, entry->effective_metric);
- g_array_append_val (changed_metrics, expected_metric);
- _LOG2D (vtable, i, entry, "sync:metric %s (%u -> %u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric,
- (guint) expected_metric);
- } else {
- if (!_vt_routes_has_entry (vtable, routes, entry)) {
- g_array_append_val (changed_metrics, entry->effective_metric);
- _LOG2D (vtable, i, entry, "sync:re-add %s (%u -> %u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric,
- (guint) entry->effective_metric);
- }
- }
-
- if (entry->effective_metric != expected_metric) {
- entry->effective_metric = expected_metric;
- changed = TRUE;
- }
- last_metric = expected_metric;
- }
-
- g_array_sort_with_data (changed_metrics, nm_cmp_uint32_p_with_data, NULL);
- last_metric = -1;
- for (j = 0; j < changed_metrics->len; j++) {
- expected_metric = g_array_index (changed_metrics, guint32, j);
-
- if (last_metric == (gint64) expected_metric) {
- /* skip duplicates. */
- continue;
- }
- changed |= _platform_route_sync_add (vtable, self, expected_metric);
- last_metric = expected_metric;
- }
-
- if ( old_entry
- && !changed_entry
- && old_entry->synced
- && !old_entry->never_default) {
- /* If we entriely remove an entry that was synced before, we must make
- * sure to flush routes for this ifindex too. Otherwise they linger
- * around as "assumed" routes */
- ifindex_to_flush = old_entry->route.rx.ifindex;
- }
-
- changed |= _platform_route_sync_flush (vtable, self, ifindex_to_flush);
-
- g_array_free (changed_metrics, TRUE);
- g_hash_table_unref (assumed_metrics);
-
- priv->resync.guard--;
- return changed;
-}
-
-static gboolean
-_entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx, const Entry *old_entry)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- Entry *entry;
- GPtrArray *entries;
-
- entries = vtable->get_entries (priv);
- g_assert (entry_idx < entries->len);
-
- entry = g_ptr_array_index (entries, entry_idx);
-
- g_assert ( !old_entry
- || (entry->source.pointer == old_entry->source.pointer && entry->route.rx.ifindex == old_entry->route.rx.ifindex));
-
- if (!entry->synced && !entry->never_default)
- entry->effective_metric = entry->route.rx.metric;
-
- _LOG2D (vtable, entry_idx, entry, "%s %s (%"G_GUINT32_FORMAT")",
- old_entry
- ? (entry != old_entry
- ? "record:update"
- : "record:resync")
- : "record:add ",
- vtable->vt->route_to_string (&entry->route, NULL, 0),
- entry->effective_metric);
-
- g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL);
-
- return _resync_all (vtable, self, entry, old_entry, FALSE);
-}
-
-static gboolean
-_entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint entry_idx)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- Entry *entry;
- GPtrArray *entries;
- gboolean ret;
-
- entries = vtable->get_entries (priv);
-
- g_assert (entry_idx < entries->len);
-
- entry = g_ptr_array_index (entries, entry_idx);
-
- _LOG2D (vtable, entry_idx, entry, "record:remove %s (%u)",
- vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric);
-
- /* Remove the entry from the list (but don't free it yet) */
- g_ptr_array_index (entries, entry_idx) = NULL;
- g_ptr_array_remove_index (entries, entry_idx);
-
- ret = _resync_all (vtable, self, NULL, entry, FALSE);
- _entry_free (entry);
-
- return ret;
-}
-
-/*****************************************************************************/
-
-static gboolean
-_ipx_update_default_route (const VTableIP *vtable,
- NMDefaultRouteManager *self,
- gpointer source)
-{
- NMDefaultRouteManagerPrivate *priv;
- Entry *entry;
- guint entry_idx;
- const NMPlatformIPRoute *default_route = NULL;
- NMPlatformIPXRoute rt;
- int ip_ifindex;
- GPtrArray *entries;
- NMDevice *device = NULL;
- NMVpnConnection *vpn = NULL;
- gboolean never_default = FALSE;
- gboolean synced = FALSE, ret;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE);
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- if (priv->disposed)
- return FALSE;
-
- if (NM_IS_DEVICE (source))
- device = source;
- else if (NM_IS_VPN_CONNECTION (source))
- vpn = source;
- else
- g_return_val_if_reached (FALSE);
-
- if (device)
- ip_ifindex = nm_device_get_ip_ifindex (device);
- else
- ip_ifindex = nm_vpn_connection_get_ip_ifindex (vpn, TRUE);
-
- entries = vtable->get_entries (priv);
- entry = _entry_find_by_source (entries, source, &entry_idx);
-
- if ( entry
- && entry->route.rx.ifindex != ip_ifindex) {
- /* Strange... the ifindex changed... Remove the device and start again. */
- _LOG2D (vtable, entry_idx, entry, "ifindex changed: %d -> %d",
- entry->route.rx.ifindex, ip_ifindex);
-
- g_object_freeze_notify (G_OBJECT (self));
- _entry_at_idx_remove (vtable, self, entry_idx);
- g_assert (!_entry_find_by_source (entries, source, NULL));
- ret = _ipx_update_default_route (vtable, self, source);
- g_object_thaw_notify (G_OBJECT (self));
- return ret;
- }
-
- /* get the @default_route from the device. */
- if (ip_ifindex > 0) {
- if (device) {
- gboolean is_assumed = FALSE;
-
- if (vtable->vt->is_ip4)
- default_route = (const NMPlatformIPRoute *) nm_device_get_ip4_default_route (device, &is_assumed);
- else
- default_route = (const NMPlatformIPRoute *) nm_device_get_ip6_default_route (device, &is_assumed);
- if (!default_route && !is_assumed) {
- /* the device has no default route, but it is not assumed. That means, NMDefaultRouteManager
- * enforces that the device has no default route.
- *
- * Hence we have to keep track of this entry, otherwise a missing entry tells us
- * that the interface is assumed and NM would not remove the default routes on
- * the device. */
- memset (&rt, 0, sizeof (rt));
- rt.rx.ifindex = ip_ifindex;
- rt.rx.rt_source = NM_IP_CONFIG_SOURCE_UNKNOWN;
- rt.rx.metric = G_MAXUINT32;
- default_route = &rt.rx;
-
- never_default = TRUE;
- }
- synced = !is_assumed;
- } else {
- NMConnection *connection = nm_active_connection_get_applied_connection ((NMActiveConnection *) vpn);
-
- if ( connection
- && nm_vpn_connection_get_vpn_state (vpn) == NM_VPN_CONNECTION_STATE_ACTIVATED) {
-
- memset (&rt, 0, sizeof (rt));
- if (vtable->vt->is_ip4) {
- NMIP4Config *vpn_config;
-
- vpn_config = nm_vpn_connection_get_ip4_config (vpn);
- if (vpn_config) {
- never_default = nm_ip4_config_get_never_default (vpn_config);
- rt.r4.ifindex = ip_ifindex;
- rt.r4.rt_source = NM_IP_CONFIG_SOURCE_VPN;
- rt.r4.gateway = nm_ip4_config_get_gateway (vpn_config);
- rt.r4.metric = nm_vpn_connection_get_ip4_route_metric (vpn);
- rt.r4.mss = nm_ip4_config_get_mss (vpn_config);
- default_route = &rt.rx;
- }
- } else {
- NMIP6Config *vpn_config;
-
- vpn_config = nm_vpn_connection_get_ip6_config (vpn);
- if (vpn_config) {
- const struct in6_addr *int_gw = nm_ip6_config_get_gateway (vpn_config);
-
- never_default = nm_ip6_config_get_never_default (vpn_config);
- rt.r6.ifindex = ip_ifindex;
- rt.r6.rt_source = NM_IP_CONFIG_SOURCE_VPN;
- rt.r6.gateway = int_gw ? *int_gw : in6addr_any;
- rt.r6.metric = nm_vpn_connection_get_ip6_route_metric (vpn);
- rt.r6.mss = nm_ip6_config_get_mss (vpn_config);
- default_route = &rt.rx;
- }
- }
- }
- if (nm_vpn_connection_get_ip_ifindex (vpn, FALSE) > 0)
- synced = TRUE;
- else {
- /* a VPN connection without tunnel device cannot have a non-synced, missing default route.
- * Either it has a default route (which is synced), or it has no entry. */
- synced = default_route && !never_default;
- }
- }
- }
-
- g_assert (!default_route || default_route->plen == 0);
-
- if (!synced && never_default) {
- /* having a non-synced, never-default entry is non-sensical. Unset
- * @default_route so that we don't add such an entry below. */
- default_route = NULL;
- }
-
- if (!entry && !default_route) {
- /* nothing to do */
- return FALSE;
- } else if (!entry) {
- /* add */
- entry = g_slice_new0 (Entry);
- entry->source.object = g_object_ref (source);
-
- if (vtable->vt->is_ip4)
- entry->route.r4 = *((const NMPlatformIP4Route *) default_route);
- else
- entry->route.r6 = *((const NMPlatformIP6Route *) default_route);
-
- /* only use normalized metrics */
- entry->route.rx.metric = vtable->vt->metric_normalize (entry->route.rx.metric);
- entry->route.rx.ifindex = ip_ifindex;
- entry->never_default = never_default;
- entry->effective_metric = entry->route.rx.metric;
- entry->synced = synced;
-
- g_ptr_array_add (entries, entry);
- return _entry_at_idx_update (vtable, self, entries->len - 1, NULL);
- } else if (default_route) {
- /* update */
- Entry old_entry, new_entry;
-
- new_entry = *entry;
- if (vtable->vt->is_ip4)
- new_entry.route.r4 = *((const NMPlatformIP4Route *) default_route);
- else
- new_entry.route.r6 = *((const NMPlatformIP6Route *) default_route);
- /* only use normalized metrics */
- new_entry.route.rx.metric = vtable->vt->metric_normalize (new_entry.route.rx.metric);
- new_entry.route.rx.ifindex = ip_ifindex;
- new_entry.never_default = never_default;
- new_entry.synced = synced;
-
- if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0) {
- if (!synced) {
- /* the internal book-keeping doesn't change, so don't do a full
- * sync of the configured routes. */
- return FALSE;
- }
- return _entry_at_idx_update (vtable, self, entry_idx, entry);
- } else {
- old_entry = *entry;
- *entry = new_entry;
- return _entry_at_idx_update (vtable, self, entry_idx, &old_entry);
- }
- } else {
- /* delete */
- return _entry_at_idx_remove (vtable, self, entry_idx);
- }
-}
-
-gboolean
-nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *self,
- gpointer source)
-{
- return _ipx_update_default_route (&vtable_ip4, self, source);
-}
-
-gboolean
-nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *self,
- gpointer source)
-{
- return _ipx_update_default_route (&vtable_ip6, self, source);
-}
-
-/*****************************************************************************/
-
-static NMDevice *
-_ipx_get_best_device (const VTableIP *vtable, NMDefaultRouteManager *self, const GSList *devices)
-{
- NMDefaultRouteManagerPrivate *priv;
- GPtrArray *entries;
- guint i;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
-
- if (!devices)
- return NULL;
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- if (priv->disposed)
- return NULL;
- entries = vtable->get_entries (priv);
-
- for (i = 0; i < entries->len; i++) {
- Entry *entry = g_ptr_array_index (entries, i);
- NMDeviceState state;
-
- if (!NM_IS_DEVICE (entry->source.pointer))
- continue;
-
- if (entry->never_default)
- continue;
-
- state = nm_device_get_state (entry->source.device);
- if ( state <= NM_DEVICE_STATE_DISCONNECTED
- || state >= NM_DEVICE_STATE_DEACTIVATING) {
- /* FIXME: we also track unmanaged devices with assumed default routes.
- * Skip them, they are (currently) no candidates for best-device.
- *
- * Later we also want to properly assume connections for unmanaged devices.
- *
- * Also, we don't want to have DEACTIVATING devices returned as best_device(). */
- continue;
- }
-
- if (g_slist_find ((GSList *) devices, entry->source.device)) {
- g_return_val_if_fail (nm_device_get_act_request (entry->source.pointer), entry->source.pointer);
- return entry->source.pointer;
- }
- }
- return NULL;
-}
-
-/** _ipx_get_best_activating_device:
- * @vtable: the virtual table
- * @self: #NMDefaultRouteManager
- * @devices: list of devices to be searched. Only devices from this list will be considered
- * @fully_activated: if #TRUE, only search for devices that are fully activated. Otherwise,
- * search if there is a best device going to be activated. In the latter case, this will
- * return NULL if the best device is already activated.
- * @preferred_device: if not-NULL, this device is preferred if there are more devices with
- * the same priority.
- **/
-static NMDevice *
-_ipx_get_best_activating_device (const VTableIP *vtable, NMDefaultRouteManager *self, const GSList *devices, NMDevice *preferred_device)
-{
- NMDefaultRouteManagerPrivate *priv;
- const GSList *iter;
- NMDevice *best_device = NULL;
- guint32 best_prio = G_MAXUINT32;
- NMDevice *best_activated_device;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- if (priv->disposed)
- return NULL;
-
- best_activated_device = _ipx_get_best_device (vtable, self, devices);
-
- for (iter = devices; iter; iter = g_slist_next (iter)) {
- NMDevice *device = NM_DEVICE (iter->data);
- guint32 prio;
- Entry *entry;
-
- entry = _entry_find_by_source (vtable->get_entries (priv), device, NULL);
-
- if (entry) {
- /* of all the device that have an entry, we already know that best_activated_device
- * is the best. entry cannot be better. */
- if (entry->source.device != best_activated_device)
- continue;
- prio = entry->effective_metric;
- } else {
- NMDeviceState state = nm_device_get_state (device);
-
- if ( state <= NM_DEVICE_STATE_DISCONNECTED
- || state >= NM_DEVICE_STATE_DEACTIVATING)
- continue;
-
- if (!nm_utils_connection_has_default_route (nm_device_get_applied_connection (device), vtable->vt->addr_family, NULL))
- continue;
-
- prio = nm_device_get_ip4_route_metric (device);
- }
- prio = vtable->vt->metric_normalize (prio);
-
- if ( !best_device
- || prio < best_prio
- || (prio == best_prio && preferred_device == device)) {
- best_device = device;
- best_prio = prio;
- }
- }
-
- /* There's only a best activating device if the best device
- * among all activating and already-activated devices is a
- * still-activating one.
- */
- if (best_device && nm_device_get_state (best_device) >= NM_DEVICE_STATE_SECONDARIES)
- return NULL;
- return best_device;
-}
-
-NMDevice *
-nm_default_route_manager_ip4_get_best_device (NMDefaultRouteManager *self, const GSList *devices, gboolean fully_activated, NMDevice *preferred_device)
-{
- if (fully_activated)
- return _ipx_get_best_device (&vtable_ip4, self, devices);
- else
- return _ipx_get_best_activating_device (&vtable_ip4, self, devices, preferred_device);
-}
-
-NMDevice *
-nm_default_route_manager_ip6_get_best_device (NMDefaultRouteManager *self, const GSList *devices, gboolean fully_activated, NMDevice *preferred_device)
-{
- if (fully_activated)
- return _ipx_get_best_device (&vtable_ip6, self, devices);
- else
- return _ipx_get_best_activating_device (&vtable_ip6, self, devices, preferred_device);
-}
-
-/*****************************************************************************/
-
-static gpointer
-_ipx_get_best_config (const VTableIP *vtable,
- NMDefaultRouteManager *self,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn)
-{
- NMDefaultRouteManagerPrivate *priv;
- GPtrArray *entries;
- guint i;
- gpointer config_result = NULL;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
-
- if (out_ip_iface)
- *out_ip_iface = NULL;
- if (out_ac)
- *out_ac = NULL;
- if (out_device)
- *out_device = NULL;
- if (out_vpn)
- *out_vpn = NULL;
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- if (priv->disposed)
- return NULL;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), NULL);
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
- entries = vtable->get_entries (priv);
-
- for (i = 0; i < entries->len; i++) {
- Entry *entry = g_ptr_array_index (entries, i);
-
- if (!NM_IS_DEVICE (entry->source.pointer)) {
- NMVpnConnection *vpn = NM_VPN_CONNECTION (entry->source.vpn);
-
- if (entry->never_default && !ignore_never_default)
- continue;
-
- if (vtable->vt->is_ip4)
- config_result = nm_vpn_connection_get_ip4_config (vpn);
- else
- config_result = nm_vpn_connection_get_ip6_config (vpn);
- g_assert (config_result);
-
- if (out_vpn)
- *out_vpn = vpn;
- if (out_ac)
- *out_ac = NM_ACTIVE_CONNECTION (vpn);
- if (out_ip_iface)
- *out_ip_iface = nm_vpn_connection_get_ip_iface (vpn, TRUE);
- } else {
- NMDevice *device = entry->source.device;
- NMActRequest *req;
- NMDeviceState state;
-
- if (entry->never_default)
- continue;
-
- state = nm_device_get_state (device);
- if ( state <= NM_DEVICE_STATE_DISCONNECTED
- || state >= NM_DEVICE_STATE_DEACTIVATING) {
- /* FIXME: the device has a default route, but we ignore it due to
- * unexpected state. That happens for example for unmanaged devices.
- *
- * In the future, we want unmanaged devices also assume a connection
- * if they are activated externally.
- *
- * Also, we don't want to have DEACTIVATING devices returned as best_config(). */
- continue;
- }
-
- if (vtable->vt->is_ip4)
- config_result = nm_device_get_ip4_config (device);
- else
- config_result = nm_device_get_ip6_config (device);
- g_assert (config_result);
- req = nm_device_get_act_request (device);
- g_assert (req);
-
- if (out_device)
- *out_device = device;
- if (out_ac)
- *out_ac = NM_ACTIVE_CONNECTION (req);
- if (out_ip_iface)
- *out_ip_iface = nm_device_get_ip_iface (device);
- }
- break;
- }
-
- return config_result;
-}
-
-NMIP4Config *
-nm_default_route_manager_ip4_get_best_config (NMDefaultRouteManager *self,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn)
-{
- return _ipx_get_best_config (&vtable_ip4,
- self,
- ignore_never_default,
- out_ip_iface,
- out_ac,
- out_device,
- out_vpn);
-}
-
-NMIP6Config *
-nm_default_route_manager_ip6_get_best_config (NMDefaultRouteManager *self,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn)
-{
- return _ipx_get_best_config (&vtable_ip6,
- self,
- ignore_never_default,
- out_ip_iface,
- out_ac,
- out_device,
- out_vpn);
-}
-
-/*****************************************************************************/
-
-static GPtrArray *
-_v4_get_entries (NMDefaultRouteManagerPrivate *priv)
-{
- return priv->entries_ip4;
-}
-
-static GPtrArray *
-_v6_get_entries (NMDefaultRouteManagerPrivate *priv)
-{
- return priv->entries_ip6;
-}
-
-static const VTableIP vtable_ip4 = {
- .vt = &nm_platform_vtable_route_v4,
- .get_entries = _v4_get_entries,
-};
-
-static const VTableIP vtable_ip6 = {
- .vt = &nm_platform_vtable_route_v6,
- .get_entries = _v6_get_entries,
-};
-
-/*****************************************************************************/
-
-static gboolean
-_resync_now (NMDefaultRouteManager *self)
-{
- gboolean has_v4_changes, has_v6_changes;
- gboolean changed = FALSE;
-
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- has_v4_changes = priv->resync.has_v4_changes;
- has_v6_changes = priv->resync.has_v6_changes;
-
- _LOGD (0, "resync: sync now (%u) (IPv4 changes: %s, IPv6 changes: %s)", priv->resync.idle_handle,
- has_v4_changes ? "yes" : "no", has_v6_changes ? "yes" : "no");
-
- priv->resync.has_v4_changes = FALSE;
- priv->resync.has_v6_changes = FALSE;
- nm_clear_g_source (&priv->resync.idle_handle);
- priv->resync.backoff_wait_time_ms =
- priv->resync.backoff_wait_time_ms == 0
- ? 100
- : priv->resync.backoff_wait_time_ms * 2;
-
- if (has_v4_changes)
- changed |= _resync_all (&vtable_ip4, self, NULL, NULL, TRUE);
-
- if (has_v6_changes)
- changed |= _resync_all (&vtable_ip6, self, NULL, NULL, TRUE);
-
- if (!changed) {
- /* Nothing changed: reset the backoff wait time */
- _resync_idle_cancel (self);
- }
-
- return changed;
-}
-
-/**
- * nm_default_route_manager_resync:
- * @self: the #NMDefaultRouteManager instance
- * @af_family: the address family to resync, can be
- * AF_INET, AF_INET6 or AF_UNSPEC to sync both.
- *
- * #NMDefaultRouteManager keeps an internal list of configured
- * routes. Usually, it configures routes in the system only
- * - when that internal list changes due to
- * nm_default_route_manager_ip4_update_default_route() or
- * nm_default_route_manager_ip6_update_default_route().
- * - when platform notifies about changes, via _resync_idle_now().
- * This forces a resync to update the internal bookkeeping
- * with what is currently configured in the system, but also
- * reconfigure the system with all non-assumed default routes.
- *
- * Returns: %TRUE if anything changed during resync.
- */
-gboolean
-nm_default_route_manager_resync (NMDefaultRouteManager *self,
- int af_family)
-{
- NMDefaultRouteManagerPrivate *priv;
-
- g_return_val_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self), FALSE);
- g_return_val_if_fail (NM_IN_SET (af_family, AF_INET, AF_INET6, AF_UNSPEC), FALSE);
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- if (priv->disposed)
- return FALSE;
-
- switch (af_family) {
- case AF_INET:
- priv->resync.has_v4_changes = TRUE;
- break;
- case AF_INET6:
- priv->resync.has_v6_changes = TRUE;
- break;
- default:
- priv->resync.has_v4_changes = TRUE;
- priv->resync.has_v6_changes = TRUE;
- break;
- }
-
- return _resync_now (self);
-}
-
-static gboolean
-_resync_idle_now (NMDefaultRouteManager *self)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- priv->resync.idle_handle = 0;
- _resync_now (self);
- return G_SOURCE_REMOVE;
-}
-
-static void
-_resync_idle_cancel (NMDefaultRouteManager *self)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- if (priv->resync.idle_handle) {
- _LOGD (0, "resync: cancelled (%u)", priv->resync.idle_handle);
- g_source_remove (priv->resync.idle_handle);
- priv->resync.idle_handle = 0;
- }
- priv->resync.backoff_wait_time_ms = 0;
- priv->resync.has_v4_changes = FALSE;
- priv->resync.has_v6_changes = FALSE;
-}
-
-static void
-_resync_idle_reschedule (NMDefaultRouteManager *self)
-{
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- /* since we react on external changes and re-add/remove default routes for
- * the interfaces we manage, there could be the erroneous situation where two applications
- * fight over a certain default route.
- * Avoid this, by increasingly wait longer to touch the system (backoff wait time). */
-
- if (priv->resync.backoff_wait_time_ms == 0) {
- /* for scheduling idle, always reschedule (to process all other events first) */
- if (priv->resync.idle_handle)
- g_source_remove (priv->resync.idle_handle);
- else
- _LOGD (0, "resync: schedule on idle");
- /* Schedule this at low priority so that on an external change to platform
- * a NMDevice has a chance to picks up the changes first. */
- priv->resync.idle_handle = g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) _resync_idle_now, self, NULL);
- } else if (!priv->resync.idle_handle) {
- priv->resync.idle_handle = g_timeout_add (priv->resync.backoff_wait_time_ms, (GSourceFunc) _resync_idle_now, self);
- _LOGD (0, "resync: schedule in %u.%03u seconds (%u)", priv->resync.backoff_wait_time_ms/1000,
- priv->resync.backoff_wait_time_ms%1000, priv->resync.idle_handle);
- }
-}
-
-static void
-_platform_changed_cb (NMPlatform *platform,
- int obj_type_i,
- int ifindex,
- gpointer platform_object,
- int change_type_i,
- NMDefaultRouteManager *self)
-{
- NMDefaultRouteManagerPrivate *priv;
- const NMPObjectType obj_type = obj_type_i;
- const VTableIP *vtable;
-
- switch (obj_type) {
- case NMP_OBJECT_TYPE_IP4_ADDRESS:
- vtable = &vtable_ip4;
- break;
- case NMP_OBJECT_TYPE_IP6_ADDRESS:
- vtable = &vtable_ip6;
- break;
- case NMP_OBJECT_TYPE_IP4_ROUTE:
- if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object))
- return;
- vtable = &vtable_ip4;
- break;
- case NMP_OBJECT_TYPE_IP6_ROUTE:
- if (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (platform_object))
- return;
- vtable = &vtable_ip6;
- break;
- default:
- g_return_if_reached ();
- }
-
- priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- if (priv->resync.guard) {
- /* callbacks while executing _resync_all() are ignored. */
- return;
- }
-
- if (vtable->vt->is_ip4)
- priv->resync.has_v4_changes = TRUE;
- else
- priv->resync.has_v6_changes = TRUE;
-
- _resync_idle_reschedule (self);
-}
-
-/*****************************************************************************/
-
-static void
-set_property (GObject *object, guint prop_id,
- const GValue *value, GParamSpec *pspec)
-{
- NMDefaultRouteManager *self = NM_DEFAULT_ROUTE_MANAGER (object);
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- switch (prop_id) {
- case PROP_LOG_WITH_PTR:
- /* construct-only */
- priv->log_with_ptr = g_value_get_boolean (value);
- break;
- case PROP_PLATFORM:
- /* construct-only */
- priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET;
- if (!priv->platform)
- g_return_if_reached ();
- g_object_ref (priv->platform);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-/*****************************************************************************/
-
-static void
-nm_default_route_manager_init (NMDefaultRouteManager *self)
-{
-}
-
-static void
-constructed (GObject *object)
-{
- NMDefaultRouteManager *self = NM_DEFAULT_ROUTE_MANAGER (object);
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- priv->entries_ip4 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free);
- priv->entries_ip6 = g_ptr_array_new_full (0, (GDestroyNotify) _entry_free);
-
- g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, G_CALLBACK (_platform_changed_cb), self);
- g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, G_CALLBACK (_platform_changed_cb), self);
- g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_platform_changed_cb), self);
- g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (_platform_changed_cb), self);
-}
-
-NMDefaultRouteManager *
-nm_default_route_manager_new (gboolean log_with_ptr, NMPlatform *platform)
-{
- return g_object_new (NM_TYPE_DEFAULT_ROUTE_MANAGER,
- NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR, log_with_ptr,
- NM_DEFAULT_ROUTE_MANAGER_PLATFORM, platform,
- NULL);
-}
-
-static void
-dispose (GObject *object)
-{
- NMDefaultRouteManager *self = NM_DEFAULT_ROUTE_MANAGER (object);
- NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
-
- priv->disposed = TRUE;
-
- if (priv->platform) {
- g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (_platform_changed_cb), self);
- g_clear_object (&priv->platform);
- }
-
- _resync_idle_cancel (self);
-
- /* g_ptr_array_free() invokes the free function for all entries without actually
- * removing them and having dangling pointers in the process. _entry_free()
- * will unref the source, which might cause the destruction of the object, which
- * might trigger calling into @self again. This is guarded by priv->dispose.
- * If you remove priv->dispose, you must refactor the lines below to remove enties
- * one-by-one.
- */
- if (priv->entries_ip4) {
- g_ptr_array_free (priv->entries_ip4, TRUE);
- priv->entries_ip4 = NULL;
- }
- if (priv->entries_ip6) {
- g_ptr_array_free (priv->entries_ip6, TRUE);
- priv->entries_ip6 = NULL;
- }
-
- G_OBJECT_CLASS (nm_default_route_manager_parent_class)->dispose (object);
-}
-
-static void
-nm_default_route_manager_class_init (NMDefaultRouteManagerClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->constructed = constructed;
- object_class->dispose = dispose;
- object_class->set_property = set_property;
-
- obj_properties[PROP_LOG_WITH_PTR] =
- g_param_spec_boolean (NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR, "", "",
- TRUE,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- obj_properties[PROP_PLATFORM] =
- g_param_spec_object (NM_DEFAULT_ROUTE_MANAGER_PLATFORM, "", "",
- NM_TYPE_PLATFORM,
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT_ONLY |
- G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
-}
diff --git a/src/nm-default-route-manager.h b/src/nm-default-route-manager.h
deleted file mode 100644
index d6ad719b0..000000000
--- a/src/nm-default-route-manager.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
-/* NetworkManager -- Network link manager
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Copyright (C) 2014 Red Hat, Inc.
- */
-
-#ifndef __NETWORKMANAGER_DEFAULT_ROUTE_MANAGER_H__
-#define __NETWORKMANAGER_DEFAULT_ROUTE_MANAGER_H__
-
-#include "nm-connection.h"
-
-#define NM_TYPE_DEFAULT_ROUTE_MANAGER (nm_default_route_manager_get_type ())
-#define NM_DEFAULT_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManager))
-#define NM_DEFAULT_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManagerClass))
-#define NM_IS_DEFAULT_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_DEFAULT_ROUTE_MANAGER))
-#define NM_IS_DEFAULT_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_DEFAULT_ROUTE_MANAGER))
-#define NM_DEFAULT_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_DEFAULT_ROUTE_MANAGER, NMDefaultRouteManagerClass))
-
-#define NM_DEFAULT_ROUTE_MANAGER_LOG_WITH_PTR "log-with-ptr"
-#define NM_DEFAULT_ROUTE_MANAGER_PLATFORM "platform"
-
-typedef struct _NMDefaultRouteManagerClass NMDefaultRouteManagerClass;
-
-GType nm_default_route_manager_get_type (void);
-
-NMDefaultRouteManager *nm_default_route_manager_new (gboolean log_with_ptr, NMPlatform *platform);
-
-gboolean nm_default_route_manager_ip4_update_default_route (NMDefaultRouteManager *manager, gpointer source);
-gboolean nm_default_route_manager_ip6_update_default_route (NMDefaultRouteManager *manager, gpointer source);
-
-NMDevice *nm_default_route_manager_ip4_get_best_device (NMDefaultRouteManager *manager, const GSList *devices, gboolean fully_activated, NMDevice *preferred_device);
-NMDevice *nm_default_route_manager_ip6_get_best_device (NMDefaultRouteManager *manager, const GSList *devices, gboolean fully_activated, NMDevice *preferred_device);
-
-NMIP4Config *nm_default_route_manager_ip4_get_best_config (NMDefaultRouteManager *manager,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn);
-NMIP6Config *nm_default_route_manager_ip6_get_best_config (NMDefaultRouteManager *manager,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn);
-
-gboolean nm_default_route_manager_resync (NMDefaultRouteManager *self,
- int af_family);
-
-#endif /* NM_DEFAULT_ROUTE_MANAGER_H */
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index cb7bb3c5a..b5b11812e 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -166,6 +166,8 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau"));
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ continue;
array[0] = route->network;
array[1] = route->plen;
array[2] = route->gateway;
@@ -235,6 +237,8 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)"));
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
+ continue;
ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&route->network,
sizeof (struct in6_addr), 1);
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 9037c2d6f..59583fa08 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -377,6 +377,7 @@ typedef struct {
GVariant *route_data_variant;
GVariant *routes_variant;
NMDedupMultiIndex *multi_idx;
+ const NMPObject *best_default_route;
union {
NMIPConfigDedupMultiIdxType idx_ip4_addresses_;
NMDedupMultiIdxType idx_ip4_addresses;
@@ -471,6 +472,95 @@ nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Conf
/*****************************************************************************/
+const NMPObject *
+_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp)
+{
+ int addr_family;
+ int c;
+ guint metric_cur, metric_cmp;
+
+ nm_assert ( !obj_cur
+ || NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cur), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
+ nm_assert ( !obj_cmp
+ || ( !obj_cur
+ && NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_cmp), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE))
+ || NMP_OBJECT_GET_TYPE (obj_cur) == NMP_OBJECT_GET_TYPE (obj_cmp));
+ nm_assert ( !obj_cur
+ || nm_ip_config_best_default_route_is (obj_cur));
+
+ /* assumes that @obj_cur is already the best default route (or NULL). It checks whether
+ * @obj_cmp is also a default route and returns the best of both. */
+ if ( obj_cmp
+ && nm_ip_config_best_default_route_is (obj_cmp)) {
+ if (!obj_cur)
+ return obj_cmp;
+
+ addr_family = NMP_OBJECT_GET_CLASS (obj_cmp)->addr_family;
+ metric_cur = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cur)->metric);
+ metric_cmp = nm_utils_ip_route_metric_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (obj_cmp)->metric);
+
+ if (metric_cmp < metric_cur)
+ return obj_cmp;
+
+ if (metric_cmp == metric_cur) {
+ /* Routes have the same metric. We still want to deterministically
+ * prefer one or the other. It's important to consistently choose one
+ * or the other, so that the order doesn't matter how routes are added
+ * (and merged). */
+ c = nmp_object_cmp (obj_cur, obj_cmp);
+ if (c != 0)
+ return c < 0 ? obj_cur : obj_cmp;
+
+ /* as last resort, compare pointers. */
+ if (obj_cmp < obj_cur)
+ return obj_cmp;
+ }
+ }
+ return obj_cur;
+}
+
+gboolean
+_nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate)
+{
+ if (new_candidate == *best_default_route)
+ return FALSE;
+ nmp_object_ref (new_candidate);
+ nm_clear_nmp_object (best_default_route);
+ *best_default_route = new_candidate;
+ return TRUE;
+}
+
+gboolean
+_nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate)
+{
+ new_candidate = _nm_ip_config_best_default_route_find_better (*best_default_route,
+ new_candidate);
+ return _nm_ip_config_best_default_route_set (best_default_route, new_candidate);
+}
+
+const NMPObject *
+nm_ip4_config_best_default_route_get (const NMIP4Config *self)
+{
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL);
+
+ return NM_IP4_CONFIG_GET_PRIVATE (self)->best_default_route;
+}
+
+const NMPObject *
+_nm_ip4_config_best_default_route_find (const NMIP4Config *self)
+{
+ NMDedupMultiIter ipconf_iter;
+ const NMPObject *new_best_default_route = NULL;
+
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, NULL) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route,
+ ipconf_iter.current->obj);
+ }
+ return new_best_default_route;
+}
+
+/*****************************************************************************/
+
static void
_notify_addresses (NMIP4Config *self)
{
@@ -487,6 +577,7 @@ _notify_routes (NMIP4Config *self)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_assert (priv->best_default_route == _nm_ip4_config_best_default_route_find (self));
nm_clear_g_variant (&priv->route_data_variant);
nm_clear_g_variant (&priv->routes_variant);
_notify (self, PROP_ROUTE_DATA);
@@ -688,8 +779,6 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
continue;
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
- continue;
_add_route (self, plobj, NULL, NULL);
}
@@ -1056,8 +1145,7 @@ nm_ip4_config_create_setting (const NMIP4Config *self)
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) {
NMIPRoute *s_route;
- /* Ignore default route. */
- if (!route->plen)
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
/* Ignore routes provided by external sources */
@@ -1133,10 +1221,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
- const NMPlatformIP4Route *route;
-
- nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &route)
- _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL);
+ nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, NULL)
+ _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
if (dst_priv->route_metric == -1)
@@ -1310,6 +1396,7 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
const NMPlatformIP4Route *r;
NMDedupMultiIter ipconf_iter;
gboolean changed;
+ gboolean changed_default_route;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@@ -1349,12 +1436,24 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
/* routes */
changed = FALSE;
+ changed_default_route = FALSE;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r),
- NULL))
+ (gconstpointer *) &obj_old)) {
+ if (dst_priv->best_default_route == obj_old) {
+ nm_clear_nmp_object (&dst_priv->best_default_route);
+ changed_default_route = TRUE;
+ }
changed = TRUE;
+ }
+ }
+ if (changed_default_route) {
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
+ _nm_ip4_config_best_default_route_find (dst));
}
if (changed)
_notify_routes (dst);
@@ -1421,16 +1520,17 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Address *a;
const NMPlatformIP4Route *r;
+ const NMPObject *new_best_default_route;
gboolean changed;
g_return_if_fail (src);
g_return_if_fail (dst);
- g_object_freeze_notify (G_OBJECT (dst));
-
dst_priv = NM_IP4_CONFIG_GET_PRIVATE (dst);
src_priv = NM_IP4_CONFIG_GET_PRIVATE (src);
+ g_object_freeze_notify (G_OBJECT (dst));
+
/* addresses */
changed = FALSE;
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) {
@@ -1459,17 +1559,24 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
/* routes */
changed = FALSE;
+ new_best_default_route = NULL;
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) {
+ const NMPObject *o = NMP_OBJECT_UP_CAST (r);
+
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip4_routes,
- NMP_OBJECT_UP_CAST (r)))
+ o)) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o);
continue;
+ }
if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
changed = TRUE;
}
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ nm_assert (changed);
if (changed)
_notify_routes (dst);
@@ -1509,6 +1616,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
const NMIP4ConfigPrivate *src_priv;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
const NMDedupMultiHeadEntry *head_entry_src;
+ const NMPObject *new_best_default_route;
g_return_val_if_fail (src != NULL, FALSE);
g_return_val_if_fail (dst != NULL, FALSE);
@@ -1627,19 +1735,25 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
}
if (!are_equal) {
has_minor_changes = TRUE;
+ new_best_default_route = NULL;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
+ const NMPObject *o = ipconf_iter_src.current->obj;
+ const NMPObject *obj_new;
+
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes_,
dst_priv->ifindex,
- ipconf_iter_src.current->obj,
+ o,
NULL,
FALSE,
TRUE,
NULL,
- NULL);
+ &obj_new);
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE);
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route);
_notify_routes (dst);
}
@@ -2028,18 +2142,12 @@ nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *new)
void
_nmtst_ip4_config_del_address (NMIP4Config *self, guint i)
{
- NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
const NMPlatformIP4Address *a;
a = _nmtst_ip4_config_get_address (self, i);
- g_return_if_fail (a);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip4_addresses,
- NMP_OBJECT_UP_CAST (a),
- NULL) != 1)
- g_return_if_reached ();
- _notify_addresses (self);
+ if (!nm_ip4_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (a)))
+ g_assert_not_reached ();
}
guint
@@ -2121,8 +2229,10 @@ nm_ip4_config_reset_routes (NMIP4Config *self)
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
- &priv->idx_ip4_routes) > 0)
+ &priv->idx_ip4_routes) > 0) {
+ nm_clear_nmp_object (&priv->best_default_route);
_notify_routes (self);
+ }
}
static void
@@ -2132,6 +2242,7 @@ _add_route (NMIP4Config *self,
const NMPObject **out_obj_new)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
const NMPObject *obj_new_2;
nm_assert ((!new) != (!obj_new));
@@ -2145,8 +2256,12 @@ _add_route (NMIP4Config *self,
(const NMPlatformObject *) new,
TRUE,
FALSE,
- NULL,
+ &obj_old,
&obj_new_2)) {
+ if ( priv->best_default_route == obj_old
+ && obj_old != obj_new_2)
+ nm_clear_nmp_object (&priv->best_default_route);
+ _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2);
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
_notify_routes (self);
} else
@@ -2172,7 +2287,7 @@ nm_ip4_config_add_route (NMIP4Config *self,
{
g_return_if_fail (self);
g_return_if_fail (new);
- g_return_if_fail (new->plen > 0 && new->plen <= 32);
+ g_return_if_fail (new->plen <= 32);
g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex > 0);
_add_route (self, NULL, new, out_obj_new);
@@ -2181,18 +2296,12 @@ nm_ip4_config_add_route (NMIP4Config *self,
void
_nmtst_ip4_config_del_route (NMIP4Config *self, guint i)
{
- NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
const NMPlatformIP4Route *r;
r = _nmtst_ip4_config_get_route (self, i);
- g_return_if_fail (r);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip4_routes,
- NMP_OBJECT_UP_CAST (r),
- NULL) != 1)
- g_return_if_reached ();
- _notify_routes (self);
+ if (!nm_ip4_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (r)))
+ g_assert_not_reached ();
}
guint
@@ -2701,6 +2810,84 @@ nm_ip4_config_get_metered (const NMIP4Config *self)
/*****************************************************************************/
+const NMPObject *
+nm_ip4_config_nmpobj_lookup (const NMIP4Config *self, const NMPObject *needle)
+{
+ const NMIP4ConfigPrivate *priv;
+ const NMDedupMultiIdxType *idx_type;
+
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), NULL);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ idx_type = &priv->idx_ip4_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ idx_type = &priv->idx_ip4_routes;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx,
+ idx_type,
+ needle));
+}
+
+gboolean
+nm_ip4_config_nmpobj_remove (NMIP4Config *self,
+ const NMPObject *needle)
+{
+ NMIP4ConfigPrivate *priv;
+ NMDedupMultiIdxType *idx_type;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ guint n;
+
+ g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
+
+ priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ idx_type = &priv->idx_ip4_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ idx_type = &priv->idx_ip4_routes;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ n = nm_dedup_multi_index_remove_obj (priv->multi_idx,
+ idx_type,
+ needle,
+ (gconstpointer *) &obj_old);
+ if (n != 1) {
+ nm_assert (n == 0);
+ return FALSE;
+ }
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle));
+
+ switch (NMP_OBJECT_GET_TYPE (obj_old)) {
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ _notify_addresses (self);
+ break;
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ if (priv->best_default_route == obj_old) {
+ _nm_ip_config_best_default_route_set (&priv->best_default_route,
+ _nm_ip4_config_best_default_route_find (self));
+ }
+ _notify_routes (self);
+ break;
+ default:
+ nm_assert_not_reached ();
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static inline void
hash_u32 (GChecksum *sum, guint32 n)
{
@@ -3056,6 +3243,8 @@ finalize (GObject *object)
NMIP4Config *self = NM_IP4_CONFIG (object);
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
+ nm_clear_nmp_object (&priv->best_default_route);
+
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_addresses);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_routes);
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 1113c9928..7db858b7b 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -75,6 +75,25 @@ nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfor
/*****************************************************************************/
+static inline gboolean
+nm_ip_config_best_default_route_is (const NMPObject *obj)
+{
+ const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (obj);
+
+ /* return whether @obj is considered a default-route, that is, a route
+ * as added by NetworkManager. E.g. if the route is not in the main-table,
+ * it's considered just like a regular route. */
+ return r
+ && !r->table_coerced
+ && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r);
+}
+
+const NMPObject *_nm_ip_config_best_default_route_find_better (const NMPObject *obj_cur, const NMPObject *obj_cmp);
+gboolean _nm_ip_config_best_default_route_set (const NMPObject **best_default_route, const NMPObject *new_candidate);
+gboolean _nm_ip_config_best_default_route_merge (const NMPObject **best_default_route, const NMPObject *new_candidate);
+
+/*****************************************************************************/
+
gboolean nm_ip_config_obj_id_equal_ip4_address (const NMPlatformIP4Address *a,
const NMPlatformIP4Address *b);
gboolean nm_ip_config_obj_id_equal_ip6_address (const NMPlatformIP6Address *a,
@@ -163,6 +182,9 @@ gboolean nm_ip4_config_has_gateway (const NMIP4Config *self);
guint32 nm_ip4_config_get_gateway (const NMIP4Config *self);
gint64 nm_ip4_config_get_route_metric (const NMIP4Config *self);
+const NMPObject *nm_ip4_config_best_default_route_get (const NMIP4Config *self);
+const NMPObject *_nm_ip4_config_best_default_route_find (const NMIP4Config *self);
+
const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self);
void nm_ip4_config_reset_addresses (NMIP4Config *self);
void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address);
@@ -234,6 +256,11 @@ NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *self);
void nm_ip4_config_set_metered (NMIP4Config *self, gboolean metered);
gboolean nm_ip4_config_get_metered (const NMIP4Config *self);
+const NMPObject *nm_ip4_config_nmpobj_lookup (const NMIP4Config *self,
+ const NMPObject *needle);
+gboolean nm_ip4_config_nmpobj_remove (NMIP4Config *self,
+ const NMPObject *needle);
+
void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only);
gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index 641e73434..3c8bf709f 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -72,6 +72,7 @@ typedef struct {
GVariant *route_data_variant;
GVariant *routes_variant;
NMDedupMultiIndex *multi_idx;
+ const NMPObject *best_default_route;
union {
NMIPConfigDedupMultiIdxType idx_ip6_addresses_;
NMDedupMultiIdxType idx_ip6_addresses;
@@ -177,6 +178,29 @@ nm_ip_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Conf
/*****************************************************************************/
+const NMPObject *
+nm_ip6_config_best_default_route_get (const NMIP6Config *self)
+{
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL);
+
+ return NM_IP6_CONFIG_GET_PRIVATE (self)->best_default_route;
+}
+
+const NMPObject *
+_nm_ip6_config_best_default_route_find (const NMIP6Config *self)
+{
+ NMDedupMultiIter ipconf_iter;
+ const NMPObject *new_best_default_route = NULL;
+
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, NULL) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route,
+ ipconf_iter.current->obj);
+ }
+ return new_best_default_route;
+}
+
+/*****************************************************************************/
+
static void
_notify_addresses (NMIP6Config *self)
{
@@ -193,6 +217,7 @@ _notify_routes (NMIP6Config *self)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_assert (priv->best_default_route == _nm_ip6_config_best_default_route_find (self));
nm_clear_g_variant (&priv->route_data_variant);
nm_clear_g_variant (&priv->routes_variant);
_notify (self, PROP_ROUTE_DATA);
@@ -478,8 +503,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
continue;
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
- continue;
_add_route (self, plobj, NULL, NULL);
}
@@ -781,8 +804,7 @@ nm_ip6_config_create_setting (const NMIP6Config *self)
if (IN6_IS_ADDR_LINKLOCAL (&route->network))
continue;
- /* Ignore default route. */
- if (!route->plen)
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
/* Ignore routes provided by external sources */
@@ -857,10 +879,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
- const NMPlatformIP6Route *route;
-
- nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &route)
- _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL, NULL);
+ nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, NULL)
+ _add_route (dst, ipconf_iter.current->obj, NULL, NULL);
}
if (dst_priv->route_metric == -1)
@@ -997,6 +1017,7 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
NMDedupMultiIter ipconf_iter;
const struct in6_addr *dst_tmp, *src_tmp;
gboolean changed;
+ gboolean changed_default_route;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@@ -1037,12 +1058,24 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
/* routes */
changed = FALSE;
+ changed_default_route = FALSE;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+
if (nm_dedup_multi_index_remove_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r),
- NULL))
+ (gconstpointer *) &obj_old)) {
+ if (dst_priv->best_default_route == obj_old) {
+ nm_clear_nmp_object (&dst_priv->best_default_route);
+ changed_default_route = TRUE;
+ }
changed = TRUE;
+ }
+ }
+ if (changed_default_route) {
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route,
+ _nm_ip6_config_best_default_route_find (dst));
}
if (changed)
_notify_routes (dst);
@@ -1088,6 +1121,7 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
const NMPlatformIP6Address *a;
const NMPlatformIP6Route *r;
gboolean changed;
+ const NMPObject *new_best_default_route;
g_return_if_fail (src);
g_return_if_fail (dst);
@@ -1128,17 +1162,24 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
/* routes */
changed = FALSE;
+ new_best_default_route = NULL;
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) {
+ const NMPObject *o = NMP_OBJECT_UP_CAST (r);
+
if (nm_dedup_multi_index_lookup_obj (src_priv->multi_idx,
&src_priv->idx_ip6_routes,
- NMP_OBJECT_UP_CAST (r)))
+ o)) {
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, o);
continue;
+ }
if (nm_dedup_multi_index_remove_entry (dst_priv->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
changed = TRUE;
}
+ if (_nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route))
+ nm_assert (changed);
if (changed)
_notify_routes (dst);
@@ -1175,6 +1216,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
const NMIP6ConfigPrivate *src_priv;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
const NMDedupMultiHeadEntry *head_entry_src;
+ const NMPObject *new_best_default_route;
g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE);
g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE);
@@ -1293,19 +1335,25 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
}
if (!are_equal) {
has_minor_changes = TRUE;
+ new_best_default_route = NULL;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
+ const NMPObject *o = ipconf_iter_src.current->obj;
+ const NMPObject *obj_new;
+
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes_,
dst_priv->ifindex,
- ipconf_iter_src.current->obj,
+ o,
NULL,
FALSE,
TRUE,
NULL,
- NULL);
+ &obj_new);
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
+ _nm_ip_config_best_default_route_set (&dst_priv->best_default_route, new_best_default_route);
_notify_routes (dst);
}
@@ -1631,18 +1679,12 @@ nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *new)
void
_nmtst_ip6_config_del_address (NMIP6Config *self, guint i)
{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Address *a;
a = _nmtst_ip6_config_get_address (self, i);
- g_return_if_fail (a);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip6_addresses,
- NMP_OBJECT_UP_CAST (a),
- NULL) != 1)
- g_return_if_reached ();
- _notify_addresses (self);
+ if (!nm_ip6_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (a)))
+ g_assert_not_reached ();
}
guint
@@ -1767,6 +1809,7 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
NMIP6ConfigPrivate *priv;
guint i;
gboolean changed = FALSE;
+ const NMPObject *new_best_default_route;
g_return_if_fail (NM_IS_IP6_CONFIG (self));
@@ -1776,9 +1819,11 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_routes);
+ new_best_default_route = NULL;
for (i = 0; i < routes_n; i++) {
const NMNDiscRoute *ndisc_route = &routes[i];
NMPObject obj;
+ const NMPObject *obj_new;
NMPlatformIP6Route *r;
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
@@ -1798,10 +1843,14 @@ nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
FALSE,
TRUE,
NULL,
- NULL))
+ &obj_new))
changed = TRUE;
+ new_best_default_route = _nm_ip_config_best_default_route_find_better (new_best_default_route, obj_new);
}
+ if (_nm_ip_config_best_default_route_set (&priv->best_default_route, new_best_default_route))
+ changed = TRUE;
+
if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0)
changed = TRUE;
@@ -1815,8 +1864,10 @@ nm_ip6_config_reset_routes (NMIP6Config *self)
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
- &priv->idx_ip6_routes) > 0)
+ &priv->idx_ip6_routes) > 0) {
+ nm_clear_nmp_object (&priv->best_default_route);
_notify_routes (self);
+ }
}
static void
@@ -1826,6 +1877,7 @@ _add_route (NMIP6Config *self,
const NMPObject **out_obj_new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
const NMPObject *obj_new_2;
nm_assert ((!new) != (!obj_new));
@@ -1839,8 +1891,12 @@ _add_route (NMIP6Config *self,
(const NMPlatformObject *) new,
TRUE,
FALSE,
- NULL,
+ &obj_old,
&obj_new_2)) {
+ if ( priv->best_default_route == obj_old
+ && obj_old != obj_new_2)
+ nm_clear_nmp_object (&priv->best_default_route);
+ _nm_ip_config_best_default_route_merge (&priv->best_default_route, obj_new_2);
NM_SET_OUT (out_obj_new, nmp_object_ref (obj_new_2));
_notify_routes (self);
} else
@@ -1866,7 +1922,7 @@ nm_ip6_config_add_route (NMIP6Config *self,
{
g_return_if_fail (self);
g_return_if_fail (new);
- g_return_if_fail (new->plen > 0 && new->plen <= 128);
+ g_return_if_fail (new->plen <= 128);
g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex > 0);
_add_route (self, NULL, new, out_obj_new);
@@ -1875,18 +1931,12 @@ nm_ip6_config_add_route (NMIP6Config *self,
void
_nmtst_ip6_config_del_route (NMIP6Config *self, guint i)
{
- NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Route *r;
r = _nmtst_ip6_config_get_route (self, i);
- g_return_if_fail (r);
-
- if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
- &priv->idx_ip6_routes,
- NMP_OBJECT_UP_CAST (r),
- NULL) != 1)
- g_return_if_reached ();
- _notify_routes (self);
+ if (!nm_ip6_config_nmpobj_remove (self,
+ NMP_OBJECT_UP_CAST (r)))
+ g_assert_not_reached ();
}
guint
@@ -2251,6 +2301,84 @@ nm_ip6_config_get_mss (const NMIP6Config *self)
/*****************************************************************************/
+const NMPObject *
+nm_ip6_config_nmpobj_lookup (const NMIP6Config *self, const NMPObject *needle)
+{
+ const NMIP6ConfigPrivate *priv;
+ const NMDedupMultiIdxType *idx_type;
+
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL);
+
+ priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ idx_type = &priv->idx_ip6_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ idx_type = &priv->idx_ip6_routes;
+ break;
+ default:
+ g_return_val_if_reached (NULL);
+ }
+
+ return nm_dedup_multi_entry_get_obj (nm_dedup_multi_index_lookup_obj (priv->multi_idx,
+ idx_type,
+ needle));
+}
+
+gboolean
+nm_ip6_config_nmpobj_remove (NMIP6Config *self,
+ const NMPObject *needle)
+{
+ NMIP6ConfigPrivate *priv;
+ NMDedupMultiIdxType *idx_type;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ guint n;
+
+ g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE);
+
+ priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ switch (NMP_OBJECT_GET_TYPE (needle)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ idx_type = &priv->idx_ip6_addresses;
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ idx_type = &priv->idx_ip6_routes;
+ break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ n = nm_dedup_multi_index_remove_obj (priv->multi_idx,
+ idx_type,
+ needle,
+ (gconstpointer *) &obj_old);
+ if (n != 1) {
+ nm_assert (n == 0);
+ return FALSE;
+ }
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_old) == NMP_OBJECT_GET_TYPE (needle));
+
+ switch (NMP_OBJECT_GET_TYPE (obj_old)) {
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ _notify_addresses (self);
+ break;
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ if (priv->best_default_route == obj_old) {
+ _nm_ip_config_best_default_route_set (&priv->best_default_route,
+ _nm_ip6_config_best_default_route_find (self));
+ }
+ _notify_routes (self);
+ break;
+ default:
+ nm_assert_not_reached ();
+ }
+ return TRUE;
+}
+
+/*****************************************************************************/
+
static inline void
hash_u32 (GChecksum *sum, guint32 n)
{
@@ -2611,6 +2739,8 @@ finalize (GObject *object)
NMIP6Config *self = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
+ nm_clear_nmp_object (&priv->best_default_route);
+
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_addresses);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes);
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index 0a7fe1749..ec8bee881 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -127,6 +127,9 @@ void nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *);
const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *self);
gint64 nm_ip6_config_get_route_metric (const NMIP6Config *self);
+const NMPObject *nm_ip6_config_best_default_route_get (const NMIP6Config *self);
+const NMPObject *_nm_ip6_config_best_default_route_find (const NMIP6Config *self);
+
const NMDedupMultiHeadEntry *nm_ip6_config_lookup_addresses (const NMIP6Config *self);
void nm_ip6_config_reset_addresses (NMIP6Config *self);
void nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *address);
@@ -184,6 +187,11 @@ gint nm_ip6_config_get_dns_priority (const NMIP6Config *self);
void nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss);
guint32 nm_ip6_config_get_mss (const NMIP6Config *self);
+const NMPObject *nm_ip6_config_nmpobj_lookup (const NMIP6Config *self,
+ const NMPObject *needle);
+gboolean nm_ip6_config_nmpobj_remove (NMIP6Config *self,
+ const NMPObject *needle);
+
void nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only);
gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b);
diff --git a/src/nm-netns.c b/src/nm-netns.c
index 8069cfccc..96ab2b355 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -26,7 +26,6 @@
#include "platform/nm-platform.h"
#include "platform/nmp-netns.h"
-#include "nm-default-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
@@ -39,7 +38,6 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
typedef struct {
NMPlatform *platform;
NMPNetns *platform_netns;
- NMDefaultRouteManager *default_route_manager;
bool log_with_ptr;
} NMNetnsPrivate;
@@ -80,12 +78,6 @@ nm_netns_get_multi_idx (NMNetns *self)
return nm_platform_get_multi_idx (NM_NETNS_GET_PRIVATE (self)->platform);
}
-NMDefaultRouteManager *
-nm_netns_get_default_route_manager (NMNetns *self)
-{
- return NM_NETNS_GET_PRIVATE (self)->default_route_manager;
-}
-
/*****************************************************************************/
static void
@@ -129,7 +121,6 @@ constructed (GObject *object)
log_with_ptr = nm_platform_get_log_with_ptr (priv->platform);
priv->platform_netns = nm_platform_netns_get (priv->platform);
- priv->default_route_manager = nm_default_route_manager_new (log_with_ptr, priv->platform);
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
}
@@ -148,7 +139,6 @@ dispose (GObject *object)
NMNetns *self = NM_NETNS (object);
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self);
- g_clear_object (&priv->default_route_manager);
g_clear_object (&priv->platform);
G_OBJECT_CLASS (nm_netns_parent_class)->dispose (object);
diff --git a/src/nm-netns.h b/src/nm-netns.h
index bc7188040..ae343cceb 100644
--- a/src/nm-netns.h
+++ b/src/nm-netns.h
@@ -39,7 +39,6 @@ NMNetns *nm_netns_new (NMPlatform *platform);
NMPlatform *nm_netns_get_platform (NMNetns *self);
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
-NMDefaultRouteManager *nm_netns_get_default_route_manager (NMNetns *self);
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c
index 2558ca0f3..08e10e40d 100644
--- a/src/nm-pacrunner-manager.c
+++ b/src/nm-pacrunner-manager.c
@@ -192,6 +192,8 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
}
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes))
+ continue;
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet4_ntop (routes->network, NULL),
routes->plen);
@@ -225,6 +227,8 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
}
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) {
+ if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (routes))
+ continue;
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet6_ntop (&routes->network, NULL),
routes->plen);
diff --git a/src/nm-policy.c b/src/nm-policy.c
index f3c915db9..8d392b223 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -31,7 +31,6 @@
#include "NetworkManagerUtils.h"
#include "nm-act-request.h"
#include "devices/nm-device.h"
-#include "nm-default-route-manager.h"
#include "nm-setting-ip4-config.h"
#include "nm-setting-connection.h"
#include "platform/nm-platform.h"
@@ -375,25 +374,81 @@ device_ip6_subnet_needed (NMDevice *device,
/*****************************************************************************/
static NMDevice *
-get_best_ip4_device (NMPolicy *self, gboolean fully_activated)
+get_best_ip_device (NMPolicy *self,
+ int addr_family,
+ gboolean fully_activated)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+ const GSList *iter;
+ NMDevice *best_device;
+ NMDevice *prev_device;
+ guint32 best_metric = G_MAXUINT32;
+ gboolean best_is_fully_activated = FALSE;
+
+ nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+
+ /* we prefer the current device in case of identical metric.
+ * Hence, try that one first.*/
+ best_device = NULL;
+ prev_device = addr_family == AF_INET
+ ? (fully_activated ? priv->default_device4 : priv->activating_device4)
+ : (fully_activated ? priv->default_device6 : priv->activating_device6);
+
+ for (iter = nm_manager_get_devices (priv->manager); iter; iter = iter->next) {
+ NMDevice *device = NM_DEVICE (iter->data);
+ NMDeviceState state;
+ const NMPObject *r;
+ NMConnection *connection;
+ guint32 metric;
+ gboolean is_fully_activated;
- return nm_default_route_manager_ip4_get_best_device (nm_netns_get_default_route_manager (priv->netns),
- nm_manager_get_devices (priv->manager),
- fully_activated,
- priv->default_device4);
-}
+ state = nm_device_get_state (device);
+ if ( state <= NM_DEVICE_STATE_DISCONNECTED
+ || state >= NM_DEVICE_STATE_DEACTIVATING)
+ continue;
-static NMDevice *
-get_best_ip6_device (NMPolicy *self, gboolean fully_activated)
-{
- NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+ if (nm_device_sys_iface_state_is_external (device))
+ continue;
+
+ r = nm_device_get_best_default_route (device, addr_family);
+ if (r) {
+ /* XXX: the best route might have rt_source NM_IP_CONFIG_SOURCE_VPN,
+ * which means it was injected by a VPN, not added by device.
+ *
+ * In this case, is it really the best device? Why do we even need the best
+ * device?? */
+ metric = nm_utils_ip_route_metric_normalize (addr_family,
+ NMP_OBJECT_CAST_IP_ROUTE (r)->metric);
+ is_fully_activated = TRUE;
+ } else if ( !fully_activated
+ && (connection = nm_device_get_applied_connection (device))
+ && nm_utils_connection_has_default_route (connection, addr_family, NULL)) {
+ metric = nm_utils_ip_route_metric_normalize (addr_family,
+ nm_device_get_ip_route_metric (device, addr_family));
+ is_fully_activated = FALSE;
+ } else
+ continue;
- return nm_default_route_manager_ip6_get_best_device (nm_netns_get_default_route_manager (priv->netns),
- nm_manager_get_devices (priv->manager),
- fully_activated,
- priv->default_device6);
+ if ( !best_device
+ || (!best_is_fully_activated && is_fully_activated)
+ || ( metric < best_metric
+ || (metric == best_metric && device == prev_device))) {
+ best_device = device;
+ best_metric = metric;
+ best_is_fully_activated = is_fully_activated;
+ }
+ }
+
+ if ( !fully_activated
+ && best_device
+ && best_is_fully_activated) {
+ /* There's only a best activating device if the best device
+ * among all activating and already-activated devices is a
+ * still-activating one. */
+ return NULL;
+ }
+
+ return best_device;
}
static gboolean
@@ -782,20 +837,83 @@ update_default_ac (NMPolicy *self,
set_active_func (best, TRUE);
}
-static NMIP4Config *
-get_best_ip4_config (NMPolicy *self,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn)
+static gpointer
+get_best_ip_config (NMPolicy *self,
+ int addr_family,
+ const char **out_ip_iface,
+ NMActiveConnection **out_ac,
+ NMDevice **out_device,
+ NMVpnConnection **out_vpn)
{
- return nm_default_route_manager_ip4_get_best_config (nm_netns_get_default_route_manager (NM_POLICY_GET_PRIVATE (self)->netns),
- ignore_never_default,
- out_ip_iface,
- out_ac,
- out_device,
- out_vpn);
+ NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
+ NMDevice *device;
+ gpointer conf;
+ const GSList *iter;
+
+ nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+
+ for (iter = nm_manager_get_active_connections (priv->manager); iter; iter = iter->next) {
+ NMActiveConnection *active = NM_ACTIVE_CONNECTION (iter->data);
+ NMVpnConnection *candidate;
+ NMVpnConnectionState vpn_state;
+
+ if (!NM_IS_VPN_CONNECTION (active))
+ continue;
+
+ candidate = NM_VPN_CONNECTION (active);
+
+ vpn_state = nm_vpn_connection_get_vpn_state (candidate);
+ if (vpn_state != NM_VPN_CONNECTION_STATE_ACTIVATED)
+ continue;
+
+ if (addr_family == AF_INET)
+ conf = nm_vpn_connection_get_ip4_config (candidate);
+ else
+ conf = nm_vpn_connection_get_ip6_config (candidate);
+ if (!conf)
+ continue;
+
+ if (addr_family == AF_INET) {
+ if (!nm_ip4_config_best_default_route_get (conf))
+ continue;
+ } else {
+ if (!nm_ip6_config_best_default_route_get (conf))
+ continue;
+ }
+
+ /* FIXME: in case of multiple VPN candidates, choose the one with the
+ * best metric. */
+ NM_SET_OUT (out_device, NULL);
+ NM_SET_OUT (out_vpn, candidate);
+ NM_SET_OUT (out_ac, active);
+ NM_SET_OUT (out_ip_iface, nm_vpn_connection_get_ip_iface (candidate, TRUE));
+ return conf;
+ }
+
+ device = get_best_ip_device (self, addr_family, TRUE);
+ if (device) {
+ NMActRequest *req;
+
+ if (addr_family == AF_INET)
+ conf = nm_device_get_ip4_config (device);
+ else
+ conf = nm_device_get_ip6_config (device);
+ req = nm_device_get_act_request (device);
+
+ if (conf && req) {
+ NM_SET_OUT (out_device, device);
+ NM_SET_OUT (out_vpn, NULL);
+ NM_SET_OUT (out_ac, NM_ACTIVE_CONNECTION (req));
+ NM_SET_OUT (out_ip_iface, nm_device_get_ip_iface (device));
+ return conf;
+ }
+ }
+
+ NM_SET_OUT (out_device, NULL);
+ NM_SET_OUT (out_vpn, NULL);
+ NM_SET_OUT (out_ac, NULL);
+ NM_SET_OUT (out_ip_iface, NULL);
+ return NULL;
}
static void
@@ -806,7 +924,7 @@ update_ip4_dns (NMPolicy *self, NMDnsManager *dns_mgr)
NMVpnConnection *vpn = NULL;
NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
- ip4_config = get_best_ip4_config (self, TRUE, &ip_iface, NULL, NULL, &vpn);
+ ip4_config = get_best_ip_config (self, AF_INET, &ip_iface, NULL, NULL, &vpn);
if (ip4_config) {
if (vpn)
dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
@@ -830,7 +948,7 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
/* Note that we might have an IPv4 VPN tunneled over an IPv6-only device,
* so we can get (vpn != NULL && best == NULL).
*/
- if (!get_best_ip4_config (self, FALSE, &ip_iface, &best_ac, &best, &vpn)) {
+ if (!get_best_ip_config (self, AF_INET, &ip_iface, &best_ac, &best, &vpn)) {
if (nm_clear_g_object (&priv->default_device4)) {
_LOGt (LOGD_DNS, "set-default-device-4: %p", NULL);
_notify (self, PROP_DEFAULT_IP4_DEVICE);
@@ -873,22 +991,6 @@ update_ip4_routing (NMPolicy *self, gboolean force_update)
_notify (self, PROP_DEFAULT_IP4_DEVICE);
}
-static NMIP6Config *
-get_best_ip6_config (NMPolicy *self,
- gboolean ignore_never_default,
- const char **out_ip_iface,
- NMActiveConnection **out_ac,
- NMDevice **out_device,
- NMVpnConnection **out_vpn)
-{
- return nm_default_route_manager_ip6_get_best_config (nm_netns_get_default_route_manager (NM_POLICY_GET_PRIVATE (self)->netns),
- ignore_never_default,
- out_ip_iface,
- out_ac,
- out_device,
- out_vpn);
-}
-
static void
update_ip6_dns_delegation (NMPolicy *self)
{
@@ -912,7 +1014,7 @@ update_ip6_dns (NMPolicy *self, NMDnsManager *dns_mgr)
NMVpnConnection *vpn = NULL;
NMDnsIPConfigType dns_type = NM_DNS_IP_CONFIG_TYPE_BEST_DEVICE;
- ip6_config = get_best_ip6_config (self, TRUE, &ip_iface, NULL, NULL, &vpn);
+ ip6_config = get_best_ip_config (self, AF_INET6, &ip_iface, NULL, NULL, &vpn);
if (ip6_config) {
if (vpn)
dns_type = NM_DNS_IP_CONFIG_TYPE_VPN;
@@ -954,7 +1056,7 @@ update_ip6_routing (NMPolicy *self, gboolean force_update)
/* Note that we might have an IPv6 VPN tunneled over an IPv4-only device,
* so we can get (vpn != NULL && best == NULL).
*/
- if (!get_best_ip6_config (self, FALSE, &ip_iface, &best_ac, &best, &vpn)) {
+ if (!get_best_ip_config (self, AF_INET6, &ip_iface, &best_ac, &best, &vpn)) {
if (nm_clear_g_object (&priv->default_device6)) {
_LOGt (LOGD_DNS, "set-default-device-6: %p", NULL);
_notify (self, PROP_DEFAULT_IP6_DEVICE);
@@ -1024,8 +1126,8 @@ check_activating_devices (NMPolicy *self)
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
NMDevice *best4, *best6 = NULL;
- best4 = get_best_ip4_device (self, FALSE);
- best6 = get_best_ip6_device (self, FALSE);
+ best4 = get_best_ip_device (self, AF_INET, FALSE);
+ best6 = get_best_ip_device (self, AF_INET6, FALSE);
g_object_freeze_notify (G_OBJECT (self));
diff --git a/src/nm-types.h b/src/nm-types.h
index 64d718b1a..bd5e249ba 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -38,7 +38,6 @@ typedef struct _NMConfigData NMConfigData;
typedef struct _NMArpingManager NMArpingManager;
typedef struct _NMConnectionProvider NMConnectionProvider;
typedef struct _NMConnectivity NMConnectivity;
-typedef struct _NMDefaultRouteManager NMDefaultRouteManager;
typedef struct _NMDevice NMDevice;
typedef struct _NMDhcp4Config NMDhcp4Config;
typedef struct _NMDhcp6Config NMDhcp6Config;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 0d40e0773..6a301765f 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -3697,11 +3697,6 @@ nm_platform_ip_route_sync (NMPlatform *self,
for (i = 0; i < plat_routes->len; i++) {
plat_o = plat_routes->pdata[i];
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (NMP_OBJECT_CAST_IP_ROUTE (plat_o))) {
- /* don't delete default routes. */
- continue;
- }
-
if ( !routes_idx
|| !g_hash_table_lookup (routes_idx, plat_o)) {
if (!nm_platform_ip_route_delete (self, plat_o)) {
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index a22a55e0a..9e4189feb 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -44,7 +44,6 @@
#include "settings/nm-agent-manager.h"
#include "nm-core-internal.h"
#include "nm-pacrunner-manager.h"
-#include "nm-default-route-manager.h"
#include "nm-firewall-manager.h"
#include "nm-config.h"
#include "nm-vpn-plugin-info.h"
@@ -498,9 +497,6 @@ _set_vpn_state (NMVpnConnection *self,
dispatcher_cleanup (self);
- nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
- nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
-
/* The connection gets destroyed by the VPN manager when it enters the
* disconnected/failed state, but we need to keep it around for a bit
* to send out signals and handle the dispatcher. So ref it.
@@ -1167,9 +1163,6 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
nm_platform_link_set_mtu (nm_netns_get_platform (priv->netns), priv->ip_ifindex, priv->mtu);
}
- nm_default_route_manager_ip4_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
- nm_default_route_manager_ip6_update_default_route (nm_netns_get_default_route_manager (priv->netns), self);
-
_LOGI ("VPN connection: (IP Config Get) complete");
if (priv->vpn_state < STATE_PRE_UP)
_set_vpn_state (self, STATE_PRE_UP, NM_ACTIVE_CONNECTION_STATE_REASON_NONE, FALSE);
@@ -1596,6 +1589,18 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
nm_connection_get_setting_ip4_config (_get_applied_connection (self)),
route_metric);
+ if (!nm_ip4_config_get_never_default (config)) {
+ const NMPlatformIP4Route r = {
+ .ifindex = ip_ifindex,
+ .rt_source = NM_IP_CONFIG_SOURCE_VPN,
+ .gateway = nm_ip4_config_get_gateway (config),
+ .metric = route_metric,
+ .mss = nm_ip4_config_get_mss (config),
+ };
+
+ nm_ip4_config_add_route (config, &r, NULL);
+ }
+
if (priv->ip4_config) {
nm_ip4_config_replace (priv->ip4_config, config, NULL);
g_object_unref (config);
@@ -1758,6 +1763,18 @@ next:
nm_connection_get_setting_ip6_config (_get_applied_connection (self)),
route_metric);
+ if (!nm_ip6_config_get_never_default (config)) {
+ const NMPlatformIP6Route r = {
+ .ifindex = ip_ifindex,
+ .rt_source = NM_IP_CONFIG_SOURCE_VPN,
+ .gateway = *(nm_ip6_config_get_gateway (config) ?: &in6addr_any),
+ .metric = route_metric,
+ .mss = nm_ip6_config_get_mss (config),
+ };
+
+ nm_ip6_config_add_route (config, &r, NULL);
+ }
+
if (priv->ip6_config) {
nm_ip6_config_replace (priv->ip6_config, config, NULL);
g_object_unref (config);