summaryrefslogtreecommitdiff
path: root/src/nm-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-manager.c')
-rw-r--r--src/nm-manager.c103
1 files changed, 75 insertions, 28 deletions
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 11809de3d2..2b14918683 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -2843,44 +2843,91 @@ device_realized (NMDevice *device,
_emit_device_added_removed (self, device, nm_device_is_real (device));
}
-static void
-device_connectivity_changed (NMDevice *device,
- GParamSpec *pspec,
- NMManager *self)
+static NMConnectivityState
+_get_best_connectivity (NMManager *self, int addr_family)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMConnectivityState best_state = NM_CONNECTIVITY_UNKNOWN;
- NMConnectivityState state;
+ NMConnectivityState best_state;
NMDevice *dev;
+ gint64 best_metric;
+
+ if (addr_family == AF_UNSPEC) {
+ best_state = _get_best_connectivity (self, AF_INET);
+ if (nm_connectivity_state_cmp (best_state, NM_CONNECTIVITY_FULL) >= 0) {
+ /* already FULL IPv4 connectivity. No need to check IPv6, it doesn't get
+ * better. */
+ return best_state;
+ }
+ return NM_MAX_WITH_CMP (nm_connectivity_state_cmp,
+ best_state,
+ _get_best_connectivity (self, AF_INET6));
+ }
- best_state = nm_device_get_connectivity_state (device);
- if (best_state < NM_CONNECTIVITY_FULL) {
- /* FIXME: is this really correct, to considere devices that don't have
- * (the best) default route for connectivity checking? */
- c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) {
- state = nm_device_get_connectivity_state (dev);
- if (nm_connectivity_state_cmp (state, best_state) <= 0)
- continue;
+ nm_assert_addr_family (addr_family);
+
+ best_state = NM_CONNECTIVITY_UNKNOWN;
+ best_metric = G_MAXINT64;
+ c_list_for_each_entry (dev, &priv->devices_lst_head, devices_lst) {
+ const NMPObject *r;
+ NMConnectivityState state;
+ gint64 metric;
+
+ r = nm_device_get_best_default_route (dev, addr_family);
+ if (r) {
+ metric = nm_utils_ip_route_metric_normalize (addr_family,
+ NMP_OBJECT_CAST_IP_ROUTE (r)->metric);
+ } else {
+ /* if all devices have no default-route, we still include the best
+ * of all connectivity state of all the devices. */
+ metric = G_MAXINT64;
+ }
+
+ if (metric > best_metric) {
+ /* we already have a default route with better metric. The connectivity state
+ * of this device is irreleavnt. */
+ continue;
+ }
+
+ state = nm_device_get_connectivity_state (dev, addr_family);
+ if (metric < best_metric) {
+ /* this device has a better default route. It wins. */
+ best_metric = metric;
best_state = state;
- if (nm_connectivity_state_cmp (best_state, NM_CONNECTIVITY_FULL) >= 0) {
- /* it doesn't get better than this. */
- break;
- }
+ } else {
+ best_state = NM_MAX_WITH_CMP (nm_connectivity_state_cmp,
+ best_state,
+ state);
+ }
+
+ if (nm_connectivity_state_cmp (best_state, NM_CONNECTIVITY_FULL) >= 0) {
+ /* it doesn't get better than FULL. We are done. */
+ break;
}
}
- nm_assert (best_state <= NM_CONNECTIVITY_FULL);
- nm_assert (nm_connectivity_state_cmp (best_state, NM_CONNECTIVITY_FULL) <= 0);
- if (best_state != priv->connectivity_state) {
- priv->connectivity_state = best_state;
+ return best_state;
+}
- _LOGD (LOGD_CORE, "connectivity checking indicates %s",
- nm_connectivity_state_to_string (priv->connectivity_state));
+static void
+device_connectivity_changed (NMDevice *device,
+ GParamSpec *pspec,
+ NMManager *self)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMConnectivityState best_state;
- nm_manager_update_state (self);
- _notify (self, PROP_CONNECTIVITY);
- nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL);
- }
+ best_state = _get_best_connectivity (self, AF_UNSPEC);
+ if (best_state == priv->connectivity_state)
+ return;
+
+ priv->connectivity_state = best_state;
+
+ _LOGD (LOGD_CORE, "connectivity checking indicates %s",
+ nm_connectivity_state_to_string (priv->connectivity_state));
+
+ nm_manager_update_state (self);
+ _notify (self, PROP_CONNECTIVITY);
+ nm_dispatcher_call_connectivity (priv->connectivity_state, NULL, NULL, NULL);
}
static void