diff options
author | Lubomir Rintel <lkundrak@v3.sk> | 2017-03-27 15:22:22 +0000 |
---|---|---|
committer | Lubomir Rintel <lkundrak@v3.sk> | 2017-03-28 15:26:47 +0200 |
commit | 6b7e9f9b225e81d365fd95901a88a7bc59c1eb39 (patch) | |
tree | 5fbaeba72e492a2c049bbda92dbc29d5190c71ef | |
parent | 9d43869e473b47542520c807dace93a6f9520964 (diff) | |
download | NetworkManager-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.c | 22 | ||||
-rw-r--r-- | src/nm-manager.c | 73 |
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); } } |