summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2017-03-27 15:22:22 +0000
committerLubomir Rintel <lkundrak@v3.sk>2017-03-28 15:26:47 +0200
commit6b7e9f9b225e81d365fd95901a88a7bc59c1eb39 (patch)
tree5fbaeba72e492a2c049bbda92dbc29d5190c71ef
parent9d43869e473b47542520c807dace93a6f9520964 (diff)
downloadNetworkManager-lr/device-conn.tar.gz
device: penalize default route metrics for connectivity failureslr/device-conn
This makes it possible to retain Internet connectivity when multiple devices have a default route, but one with the link type of a higher priority can not reach the Internet.
-rw-r--r--src/devices/nm-device.c22
-rw-r--r--src/nm-manager.c73
2 files changed, 65 insertions, 30 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 0f92d42dd4..2cba9fddbb 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -1480,6 +1480,17 @@ nm_device_get_priority (NMDevice *self)
return 11000;
}
+static int
+default_route_penalty (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ if (priv->connectivity_state != NM_CONNECTIVITY_FULL)
+ return 20000;
+ else
+ return 0;
+}
+
static guint32
_get_ipx_route_metric (NMDevice *self,
gboolean is_v4)
@@ -1728,6 +1739,11 @@ update_connectivity_state (NMDevice *self, NMConnectivityState state)
#endif
priv->connectivity_state = state;
_notify (self, PROP_CONNECTIVITY);
+
+ if (!ip4_config_merge_and_apply (self, NULL, TRUE))
+ _LOGW (LOGD_IP4, "Failed to update IPv4 default route metric");
+ if (!ip6_config_merge_and_apply (self, TRUE))
+ _LOGW (LOGD_IP6, "Failed to update IPv6 default route metric");
}
}
@@ -1851,9 +1867,9 @@ concheck_periodic_update (NMDevice *self)
nm_device_check_connectivity (self, NULL, NULL);
} else if (!check_enable && priv->concheck_periodic_id) {
/* The default route has gone off, and so has connectivity. */
- update_connectivity_state (self, NM_CONNECTIVITY_NONE);
g_signal_handler_disconnect (nm_connectivity_get (), priv->concheck_periodic_id);
priv->concheck_periodic_id = 0;
+ update_connectivity_state (self, NM_CONNECTIVITY_NONE);
}
#else
/* update_connectivity_state() figures out how to lie about
@@ -5489,7 +5505,7 @@ ip4_config_merge_and_apply (NMDevice *self,
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 = default_route_metric;
+ priv->default_route.v4.metric = default_route_metric + default_route_penalty (self);
priv->default_route.v4.mss = nm_ip4_config_get_mss (composite);
if (!has_direct_route) {
@@ -6236,7 +6252,7 @@ ip6_config_merge_and_apply (NMDevice *self,
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 = nm_device_get_ip6_route_metric (self);
+ priv->default_route.v6.metric = nm_device_get_ip6_route_metric (self) + default_route_penalty (self);
priv->default_route.v6.mss = nm_ip6_config_get_mss (composite);
if (!has_direct_route) {
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 3b873bd4d4..e75e499a2e 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -1968,20 +1968,23 @@ device_realized (NMDevice *device,
#if WITH_CONCHECK
static void
-nm_manager_update_connectivity_state (NMManager *self)
+device_connectivity_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMConnectivityState state = NM_CONNECTIVITY_UNKNOWN;
- NMDevice *device;
+ NMConnectivityState best_state = NM_CONNECTIVITY_UNKNOWN;
+ NMConnectivityState state;
+ const GSList *devices;
- if (priv->primary_connection) {
- device = nm_active_connection_get_device (priv->primary_connection);
- if (device)
- state = nm_device_get_connectivity_state (device);
+ for (devices = priv->devices; devices; devices = devices->next) {
+ state = nm_device_get_connectivity_state (NM_DEVICE (devices->data));
+ if (state > best_state)
+ best_state = state;
}
- if (state != priv->connectivity_state) {
- priv->connectivity_state = state;
+ if (best_state != priv->connectivity_state) {
+ priv->connectivity_state = best_state;
_LOGD (LOGD_CORE, "connectivity checking indicates %s",
nm_connectivity_state_to_string (priv->connectivity_state));
@@ -1991,14 +1994,6 @@ nm_manager_update_connectivity_state (NMManager *self)
nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL);
}
}
-
-static void
-device_connectivity_changed (NMDevice *device,
- GParamSpec *pspec,
- NMManager *self)
-{
- nm_manager_update_connectivity_state (self);
-}
#endif
static void
@@ -4825,13 +4820,35 @@ impl_manager_get_logging (NMManager *manager,
nm_logging_domains_to_string ()));
}
+typedef struct {
+ guint remaining;
+ GDBusMethodInvocation *context;
+ NMConnectivityState state;
+} ConnectivityCheckData;
+
static void
device_connectivity_done (NMDevice *device, NMConnectivityState state, gpointer user_data)
{
- GDBusMethodInvocation *context = user_data;
+ ConnectivityCheckData *data = user_data;
- g_dbus_method_invocation_return_value (context,
- g_variant_new ("(u)", state));
+ data->remaining--;
+
+ /* We check if the state is already FULL so that we can provide the
+ * response without waiting for slower devices that are not going to
+ * affect the overall state anyway. */
+
+ if (data->state != NM_CONNECTIVITY_FULL) {
+ if (state > data->state)
+ data->state = state;
+
+ if (data->state == NM_CONNECTIVITY_FULL || !data->remaining) {
+ g_dbus_method_invocation_return_value (data->context,
+ g_variant_new ("(u)", data->state));
+ }
+ }
+
+ if (!data->remaining)
+ g_slice_free (ConnectivityCheckData, data);
}
static void
@@ -4844,6 +4861,8 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
NMAuthCallResult result;
+ ConnectivityCheckData *data;
+ const GSList *devices;
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
@@ -4861,13 +4880,14 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
"Not authorized to recheck connectivity");
} else {
/* it's allowed */
- if (priv->primary_connection) {
- nm_device_check_connectivity (nm_active_connection_get_device (priv->primary_connection),
+ data = g_slice_new0 (ConnectivityCheckData);
+ data->context = context;
+
+ for (devices = priv->devices; devices; devices = devices->next) {
+ data->remaining++;
+ nm_device_check_connectivity (NM_DEVICE (devices->data),
device_connectivity_done,
- context);
- } else {
- g_dbus_method_invocation_return_value (context,
- g_variant_new ("(u)", priv->connectivity_state));
+ data);
}
}
@@ -5153,7 +5173,6 @@ policy_default_device_changed (GObject *object, GParamSpec *pspec, gpointer user
_notify (self, PROP_PRIMARY_CONNECTION);
_notify (self, PROP_PRIMARY_CONNECTION_TYPE);
nm_manager_update_metered (self);
- nm_manager_update_connectivity_state (self);
}
}