summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2014-11-04 10:26:01 +0100
committerThomas Haller <thaller@redhat.com>2014-11-07 15:23:12 +0100
commita39a3ae4cd72d695f1b5d10eaa79544f2020a54e (patch)
tree1fadcbeff158b9c1d088e2501c29d6e993d27dde
parenta94605f92b7dc25dcb8f574da0e48e44e9fdcf29 (diff)
downloadNetworkManager-a39a3ae4cd72d695f1b5d10eaa79544f2020a54e.tar.gz
policy: track default route for VPN in NMDefaultRouteManager
Extend NMDefaultRouteManager to track NMVpnConnection beside NMDevice. That way, all default routes are managed by NMDefaultRouteManager. For VPN connections the manager also tracks connections that are set never_default. That is useful because NMPolicy still uses VPNs without default route to setup DNS. Hence, NMDefaultRouteManager trackes those connections to have the relative priority of the devices. Interestingly, that means that for VPNs that are ipv4.never-default, ipv4.route-metric still has an effect in determining relative priorities for DNS configuration. This commit only adds the parts to track the default route. NMPolicy still sets the route as before. Signed-off-by: Thomas Haller <thaller@redhat.com>
-rw-r--r--src/nm-default-route-manager.c114
-rw-r--r--src/vpn-manager/nm-vpn-connection.c10
2 files changed, 111 insertions, 13 deletions
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
index ac00ab21e1..8c0529e356 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -27,6 +27,7 @@
#include "nm-logging.h"
#include "nm-device.h"
+#include "nm-vpn-connection.h"
#include "nm-platform.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
@@ -72,7 +73,7 @@ static NMDefaultRouteManager *_instance;
entry_idx, \
NM_IS_DEVICE (entry->source.pointer) ? "dev" : "vpn", \
entry->source.pointer, \
- nm_device_get_iface (entry->source.device)
+ NM_IS_DEVICE (entry->source.pointer) ? nm_device_get_iface (entry->source.device) : nm_vpn_connection_get_connection_id (entry->source.vpn)
/***********************************************************************************/
@@ -81,6 +82,7 @@ typedef struct {
void *pointer;
GObject *object;
NMDevice *device;
+ NMVpnConnection *vpn;
} source;
union {
NMPlatformIPRoute route;
@@ -88,6 +90,12 @@ typedef struct {
NMPlatformIP6Route route6;
};
gboolean synced; /* if true, we synced the entry to platform. We don't sync assumed devices */
+
+ /* it makes sense to order sources based on their priority, without
+ * actually adding a default route. This is useful to decide which
+ * DNS server to prefer. never_default entries are not synced to platform. */
+ gboolean never_default;
+
guint32 effective_metric;
} Entry;
@@ -148,6 +156,9 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
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;
@@ -215,6 +226,9 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self)
for (i = 0; i < entries->len; i++) {
Entry *e = g_ptr_array_index (entries, i);
+ if (e->never_default)
+ continue;
+
if ( e->route.ifindex == route->ifindex
&& e->synced) {
has_ifindex_synced = TRUE;
@@ -253,6 +267,10 @@ _sort_entries_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
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.
@@ -300,6 +318,9 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
g_assert (entry != old_entry);
+ if (entry->never_default)
+ continue;
+
if (!entry->synced) {
last_metric = MAX (last_metric, (gint64) entry->effective_metric);
continue;
@@ -342,7 +363,7 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
{
NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
Entry *entry;
- NMDevice *device;
+ NMDevice *device = NULL;
GPtrArray *entries;
entries = vtable->get_entries (priv);
@@ -350,8 +371,8 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
entry = g_ptr_array_index (entries, entry_idx);
- g_return_if_fail (NM_IS_DEVICE (entry->source.pointer));
- device = entry->source.device;
+ if (NM_IS_DEVICE (entry->source.pointer))
+ device = entry->source.device;
g_assert ( !old_entry
|| (entry->source.pointer == old_entry->source.pointer && entry->route.ifindex == old_entry->route.ifindex));
@@ -362,7 +383,7 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
LOG_ENTRY_ARGS (entry_idx, entry),
old_entry ? "update" : "add",
vtable->platform_route_to_string (&entry->route),
- entry->synced ? "" : " (not synced)");
+ entry->never_default ? " (never-default)" : (entry->synced ? "" : " (not synced)"));
}
g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL);
@@ -403,18 +424,38 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
Entry *entry;
guint entry_idx;
const NMPlatformIPRoute *default_route = NULL;
+ union {
+ NMPlatformIPRoute vx;
+ NMPlatformIP4Route v4;
+ NMPlatformIP6Route v6;
+ } rt;
int ip_ifindex;
GPtrArray *entries;
NMDevice *device = NULL;
+ NMVpnConnection *vpn = NULL;
+ gboolean never_default = FALSE;
gboolean synced;
g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self));
if (NM_IS_DEVICE (source))
device = source;
+ else if (NM_IS_VPN_CONNECTION (source))
+ vpn = source;
else
g_return_if_reached ();
- ip_ifindex = nm_device_get_ip_ifindex (device);
+ if (device)
+ ip_ifindex = nm_device_get_ip_ifindex (device);
+ else {
+ ip_ifindex = nm_vpn_connection_get_ip_ifindex (vpn);
+
+ if (ip_ifindex <= 0) {
+ NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
+
+ if (parent)
+ ip_ifindex = nm_device_get_ip_ifindex (parent);
+ }
+ }
priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
@@ -438,15 +479,60 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
/* get the @default_route from the device. */
if (ip_ifindex > 0) {
- if (VTABLE_IS_IP4)
- default_route = (const NMPlatformIPRoute *) nm_device_get_ip4_default_route (device);
- else
- default_route = (const NMPlatformIPRoute *) nm_device_get_ip6_default_route (device);
+ if (device) {
+ if (VTABLE_IS_IP4)
+ default_route = (const NMPlatformIPRoute *) nm_device_get_ip4_default_route (device);
+ else
+ default_route = (const NMPlatformIPRoute *) nm_device_get_ip6_default_route (device);
+ } else {
+ NMConnection *connection = nm_active_connection_get_connection ((NMActiveConnection *) vpn);
+
+ if ( connection
+ && nm_vpn_connection_get_vpn_state (vpn) == NM_VPN_CONNECTION_STATE_ACTIVATED) {
+
+ if (VTABLE_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);
+ memset (&rt.v4, 0, sizeof (rt.v4));
+ rt.v4.ifindex = ip_ifindex;
+ rt.v4.source = NM_IP_CONFIG_SOURCE_VPN;
+ rt.v4.gateway = nm_vpn_connection_get_ip4_internal_gateway (vpn);
+ rt.v4.metric = nm_vpn_connection_get_ip4_route_metric (vpn);
+ rt.v4.mss = nm_ip4_config_get_mss (vpn_config);
+ default_route = &rt.vx;
+ }
+ } else {
+ NMIP6Config *vpn_config;
+
+ vpn_config = nm_vpn_connection_get_ip6_config (vpn);
+ if (vpn_config) {
+ const struct in6_addr *int_gw = nm_vpn_connection_get_ip6_internal_gateway (vpn);
+
+ never_default = nm_ip6_config_get_never_default (vpn_config);
+ memset (&rt.v6, 0, sizeof (rt.v6));
+ rt.v6.ifindex = ip_ifindex;
+ rt.v6.source = NM_IP_CONFIG_SOURCE_VPN;
+ rt.v6.gateway = int_gw ? *int_gw : in6addr_any;
+ rt.v6.metric = nm_vpn_connection_get_ip6_route_metric (vpn);
+ rt.v6.mss = nm_ip6_config_get_mss (vpn_config);
+ default_route = &rt.vx;
+ }
+ }
+ }
+
+ /* FIXME: for now, only track the default route for VPN.
+ * Enable actual configuration of the route later. */
+ never_default = TRUE;
+ }
}
g_assert (!default_route || default_route->plen == 0);
- /* if the device uses an assumed connection, we don't sync the route. */
- synced = !nm_device_uses_assumed_connection (device);
+ /* if the source is never_default or the device uses an assumed connection,
+ * we don't sync the route. */
+ synced = !never_default && (!device || !nm_device_uses_assumed_connection (device));
if (!entry && !default_route)
/* nothing to do */;
@@ -463,6 +549,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
/* only use normalized metrics */
entry->route.metric = vtable->route_metric_normalize (entry->route.metric);
entry->route.ifindex = ip_ifindex;
+ entry->never_default = never_default;
entry->effective_metric = entry->route.metric;
entry->synced = synced;
@@ -480,6 +567,7 @@ _ipx_update_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
/* only use normalized metrics */
new_entry.route.metric = vtable->route_metric_normalize (new_entry.route.metric);
new_entry.route.ifindex = ip_ifindex;
+ new_entry.never_default = never_default;
new_entry.synced = synced;
if (memcmp (entry, &new_entry, sizeof (new_entry)) == 0)
@@ -515,7 +603,7 @@ _ipx_remove_default_route (const VTableIP *vtable, NMDefaultRouteManager *self,
guint entry_idx;
g_return_if_fail (NM_IS_DEFAULT_ROUTE_MANAGER (self));
- g_return_if_fail (NM_IS_DEVICE (source));
+ g_return_if_fail (NM_IS_DEVICE (source) || NM_IS_VPN_CONNECTION (source));
priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 444b1948d4..fe5d812791 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -41,6 +41,7 @@
#include "nm-dispatcher.h"
#include "nm-agent-manager.h"
#include "nm-core-internal.h"
+#include "nm-default-route-manager.h"
#include "nm-vpn-connection-glue.h"
@@ -234,6 +235,9 @@ vpn_cleanup (NMVpnConnection *connection, NMDevice *parent_dev)
nm_platform_address_flush (priv->ip_ifindex);
}
+ nm_default_route_manager_ip4_remove_default_route (nm_default_route_manager_get (), connection);
+ nm_default_route_manager_ip6_remove_default_route (nm_default_route_manager_get (), connection);
+
nm_device_set_vpn4_config (parent_dev, NULL);
nm_device_set_vpn6_config (parent_dev, NULL);
@@ -338,6 +342,9 @@ _set_vpn_state (NMVpnConnection *connection,
g_object_notify (G_OBJECT (connection), NM_VPN_CONNECTION_VPN_STATE);
}
+ nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), connection);
+ nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), connection);
+
switch (vpn_state) {
case STATE_NEED_AUTH:
/* Do nothing; not part of 'default' because we don't want to touch
@@ -942,6 +949,9 @@ nm_vpn_connection_apply_config (NMVpnConnection *connection)
apply_parent_device_config (connection);
+ nm_default_route_manager_ip4_update_default_route (nm_default_route_manager_get (), connection);
+ nm_default_route_manager_ip6_update_default_route (nm_default_route_manager_get (), connection);
+
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
nm_connection_get_id (priv->connection));
_set_vpn_state (connection, STATE_PRE_UP, NM_VPN_CONNECTION_STATE_REASON_NONE, FALSE);