connectivity: allow limiting the connectivity check to a specified AF

Nothing changes practically, as the NMDevice still starts this with
AF_UNSPEC. That is going to change in the following commit.

The ugly part:

priv->concheck_x[0] in few places. I believe we shouldn't be using union
aliasing here, and instead of indexing the v4/v6 arrays by a boolean it
should be an enum. I'm not fixing it here, but I eventually plan to if
this gets an ACK.
This commit is contained in:
Lubomir Rintel
2018-07-03 19:20:45 +02:00
parent 2cec94bacc
commit 9664f284a1
5 changed files with 176 additions and 106 deletions

View File

@@ -175,6 +175,7 @@ struct _NMDeviceConnectivityHandle {
bool is_periodic:1; bool is_periodic:1;
bool is_periodic_bump:1; bool is_periodic_bump:1;
bool is_periodic_bump_on_complete:1; bool is_periodic_bump_on_complete:1;
int addr_family;
}; };
typedef struct { typedef struct {
@@ -555,24 +556,24 @@ typedef struct _NMDevicePrivate {
NMLldpListener *lldp_listener; NMLldpListener *lldp_listener;
NMConnectivity *concheck_mgr; NMConnectivity *concheck_mgr;
/* if periodic checks are enabled, this is the source id for the next check. */
guint concheck_p_cur_id;
/* the currently configured max periodic interval. */
guint concheck_p_max_interval;
/* the current interval. If we are probing, the interval might be lower
* then the configured max interval. */
guint concheck_p_cur_interval;
/* the timestamp, when we last scheduled the timer concheck_p_cur_id with current interval
* concheck_p_cur_interval. */
gint64 concheck_p_cur_basetime_ns;
NMConnectivityState connectivity_state;
CList concheck_lst_head; CList concheck_lst_head;
struct {
/* if periodic checks are enabled, this is the source id for the next check. */
guint p_cur_id;
/* the currently configured max periodic interval. */
guint p_max_interval;
/* the current interval. If we are probing, the interval might be lower
* then the configured max interval. */
guint p_cur_interval;
/* the timestamp, when we last scheduled the timer p_cur_id with current interval
* p_cur_interval. */
gint64 p_cur_basetime_ns;
NMConnectivityState state;
} concheck_x[2];
guint check_delete_unrealized_id; guint check_delete_unrealized_id;
@@ -643,7 +644,10 @@ static void _set_mtu (NMDevice *self, guint32 mtu);
static void _commit_mtu (NMDevice *self, const NMIP4Config *config); static void _commit_mtu (NMDevice *self, const NMIP4Config *config);
static void _cancel_activation (NMDevice *self); static void _cancel_activation (NMDevice *self);
static void concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean is_periodic); static void concheck_update_state (NMDevice *self,
int addr_family,
NMConnectivityState state,
gboolean is_periodic);
/*****************************************************************************/ /*****************************************************************************/
@@ -2092,13 +2096,14 @@ nm_device_get_route_metric_default (NMDeviceType device_type)
} }
static gboolean static gboolean
default_route_metric_penalty_detect (NMDevice *self) default_route_metric_penalty_detect (NMDevice *self, int addr_family)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const gboolean IS_IPv4 = (addr_family == AF_INET);
/* currently we don't differentiate between IPv4 and IPv6 when detecting /* currently we don't differentiate between IPv4 and IPv6 when detecting
* connectivity. */ * connectivity. */
if ( priv->connectivity_state != NM_CONNECTIVITY_FULL if ( priv->concheck_x[IS_IPv4].state != NM_CONNECTIVITY_FULL
&& nm_connectivity_check_enabled (concheck_get_mgr (self))) && nm_connectivity_check_enabled (concheck_get_mgr (self)))
return TRUE; return TRUE;
@@ -2448,23 +2453,35 @@ typedef enum {
} ConcheckScheduleMode; } ConcheckScheduleMode;
static NMDeviceConnectivityHandle *concheck_start (NMDevice *self, static NMDeviceConnectivityHandle *concheck_start (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback, NMDeviceConnectivityCallback callback,
gpointer user_data, gpointer user_data,
gboolean is_periodic); gboolean is_periodic);
static void concheck_periodic_schedule_set (NMDevice *self, static void concheck_periodic_schedule_set (NMDevice *self,
int addr_family,
ConcheckScheduleMode mode); ConcheckScheduleMode mode);
static gboolean static gboolean
concheck_periodic_timeout_cb (gpointer user_data) _concheck_periodic_timeout_cb (NMDevice *self, int addr_family)
{ {
NMDevice *self = user_data;
_LOGt (LOGD_CONCHECK, "connectivity: periodic timeout"); _LOGt (LOGD_CONCHECK, "connectivity: periodic timeout");
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_PERIODIC); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_PERIODIC);
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
static gboolean
concheck_ip4_periodic_timeout_cb (gpointer user_data)
{
return _concheck_periodic_timeout_cb (user_data, AF_INET);
}
static gboolean
concheck_ip6_periodic_timeout_cb (gpointer user_data)
{
return _concheck_periodic_timeout_cb (user_data, AF_INET6);
}
static gboolean static gboolean
concheck_is_possible (NMDevice *self) concheck_is_possible (NMDevice *self)
{ {
@@ -2483,17 +2500,18 @@ concheck_is_possible (NMDevice *self)
} }
static gboolean static gboolean
concheck_periodic_schedule_do (NMDevice *self, gint64 now_ns) concheck_periodic_schedule_do (NMDevice *self, int addr_family, gint64 now_ns)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gboolean periodic_check_disabled = FALSE; gboolean periodic_check_disabled = FALSE;
gint64 expiry, tdiff; gint64 expiry, tdiff;
const gboolean IS_IPv4 = (addr_family == AF_INET);
/* we always cancel whatever was pending. */ /* we always cancel whatever was pending. */
if (nm_clear_g_source (&priv->concheck_p_cur_id)) if (nm_clear_g_source (&priv->concheck_x[IS_IPv4].p_cur_id))
periodic_check_disabled = TRUE; periodic_check_disabled = TRUE;
if (priv->concheck_p_max_interval == 0) { if (priv->concheck_x[IS_IPv4].p_max_interval == 0) {
/* periodic checks are disabled */ /* periodic checks are disabled */
goto out; goto out;
} }
@@ -2502,23 +2520,24 @@ concheck_periodic_schedule_do (NMDevice *self, gint64 now_ns)
goto out; goto out;
nm_assert (now_ns > 0); nm_assert (now_ns > 0);
nm_assert (priv->concheck_p_cur_interval > 0); nm_assert (priv->concheck_x[IS_IPv4].p_cur_interval > 0);
/* we schedule the timeout based on our current settings cur-interval and cur-basetime. /* we schedule the timeout based on our current settings cur-interval and cur-basetime.
* Before calling concheck_periodic_schedule_do(), make sure that these properties are * Before calling concheck_periodic_schedule_do(), make sure that these properties are
* correct. */ * correct. */
expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND);
tdiff = expiry - now_ns; tdiff = expiry - now_ns;
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: %sscheduled in %lld milliseconds (%u seconds interval)", _LOGT (LOGD_CONCHECK, "connectivity: periodic-check: %sscheduled in %lld milliseconds (%u seconds interval)",
periodic_check_disabled ? "re-" : "", periodic_check_disabled ? "re-" : "",
(long long) (tdiff / NM_UTILS_NS_PER_MSEC), (long long) (tdiff / NM_UTILS_NS_PER_MSEC),
priv->concheck_p_cur_interval); priv->concheck_x[IS_IPv4].p_cur_interval);
priv->concheck_p_cur_id = g_timeout_add (NM_MAX ((gint64) 0, tdiff) / NM_UTILS_NS_PER_MSEC, priv->concheck_x[IS_IPv4].p_cur_id =
concheck_periodic_timeout_cb, g_timeout_add (NM_MAX ((gint64) 0, tdiff) / NM_UTILS_NS_PER_MSEC,
self); IS_IPv4 ? concheck_ip4_periodic_timeout_cb : concheck_ip6_periodic_timeout_cb,
self);
return TRUE; return TRUE;
out: out:
if (periodic_check_disabled) if (periodic_check_disabled)
@@ -2529,19 +2548,19 @@ out:
#define CONCHECK_P_PROBE_INTERVAL 1 #define CONCHECK_P_PROBE_INTERVAL 1
static void static void
concheck_periodic_schedule_set (NMDevice *self, concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckScheduleMode mode)
ConcheckScheduleMode mode)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gint64 new_expiry, exp_expiry, cur_expiry, tdiff; gint64 new_expiry, exp_expiry, cur_expiry, tdiff;
gint64 now_ns = 0; gint64 now_ns = 0;
const gboolean IS_IPv4 = (addr_family == AF_INET);
if (priv->concheck_p_max_interval == 0) { if (priv->concheck_x[IS_IPv4].p_max_interval == 0) {
/* periodic check is disabled. Nothing to do. */ /* periodic check is disabled. Nothing to do. */
return; return;
} }
if (!priv->concheck_p_cur_id) { if (!priv->concheck_x[IS_IPv4].p_cur_id) {
/* we currently don't have a timeout scheduled. No need to reschedule /* we currently don't have a timeout scheduled. No need to reschedule
* another one... */ * another one... */
if (NM_IN_SET (mode, CONCHECK_SCHEDULE_UPDATE_INTERVAL, if (NM_IN_SET (mode, CONCHECK_SCHEDULE_UPDATE_INTERVAL,
@@ -2555,19 +2574,19 @@ concheck_periodic_schedule_set (NMDevice *self,
switch (mode) { switch (mode) {
case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART: case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL); priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL);
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); priv->concheck_x[IS_IPv4].p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
if (concheck_periodic_schedule_do (self, now_ns)) if (concheck_periodic_schedule_do (self, addr_family, now_ns))
concheck_start (self, NULL, NULL, TRUE); concheck_start (self, addr_family, NULL, NULL, TRUE);
return; return;
case CONCHECK_SCHEDULE_UPDATE_INTERVAL: case CONCHECK_SCHEDULE_UPDATE_INTERVAL:
/* called with "UPDATE_INTERVAL" and already have a concheck_p_cur_id scheduled. */ /* called with "UPDATE_INTERVAL" and already have a p_cur_id scheduled. */
nm_assert (priv->concheck_p_max_interval > 0); nm_assert (priv->concheck_x[IS_IPv4].p_max_interval > 0);
nm_assert (priv->concheck_p_cur_interval > 0); nm_assert (priv->concheck_x[IS_IPv4].p_cur_interval > 0);
if (priv->concheck_p_cur_interval <= priv->concheck_p_max_interval) { if (priv->concheck_x[IS_IPv4].p_cur_interval <= priv->concheck_x[IS_IPv4].p_max_interval) {
/* we currently have a shorter interval set, than what we now have. Either, /* we currently have a shorter interval set, than what we now have. Either,
* because we are probing, or because the previous max interval was shorter. * because we are probing, or because the previous max interval was shorter.
* *
@@ -2576,17 +2595,17 @@ concheck_periodic_schedule_set (NMDevice *self,
return; return;
} }
cur_expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_max_interval * NM_UTILS_NS_PER_SECOND); cur_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_max_interval * NM_UTILS_NS_PER_SECOND);
nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
priv->concheck_p_cur_interval = priv->concheck_p_max_interval; priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval;
if (cur_expiry <= now_ns) { if (cur_expiry <= now_ns) {
/* Since the last time we scheduled a periodic check, already more than the /* Since the last time we scheduled a periodic check, already more than the
* new max_interval passed. We need to start a check right away (and * new max_interval passed. We need to start a check right away (and
* schedule a timeout in cur-interval in the future). */ * schedule a timeout in cur-interval in the future). */
priv->concheck_p_cur_basetime_ns = now_ns; priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns;
if (concheck_periodic_schedule_do (self, now_ns)) if (concheck_periodic_schedule_do (self, addr_family, now_ns))
concheck_start (self, NULL, NULL, TRUE); concheck_start (self, addr_family, NULL, NULL, TRUE);
} else { } else {
/* we are reducing the max-interval to a shorter interval that we have currently /* we are reducing the max-interval to a shorter interval that we have currently
* scheduled (with cur_interval). * scheduled (with cur_interval).
@@ -2594,24 +2613,26 @@ concheck_periodic_schedule_set (NMDevice *self,
* However, since the last time we scheduled the check, not even the new max-interval * However, since the last time we scheduled the check, not even the new max-interval
* expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime * expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime
* is unchanged. */ * is unchanged. */
concheck_periodic_schedule_do (self, now_ns); concheck_periodic_schedule_do (self, addr_family, now_ns);
} }
return; return;
case CONCHECK_SCHEDULE_CHECK_EXTERNAL: case CONCHECK_SCHEDULE_CHECK_EXTERNAL:
/* a external connectivity check delays our periodic check. We reset the counter. */ /* a external connectivity check delays our periodic check. We reset the counter. */
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); priv->concheck_x[IS_IPv4].p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
concheck_periodic_schedule_do (self, now_ns); concheck_periodic_schedule_do (self, addr_family, now_ns);
return; return;
case CONCHECK_SCHEDULE_CHECK_PERIODIC: case CONCHECK_SCHEDULE_CHECK_PERIODIC:
{ {
gboolean any_periodic_pending; gboolean any_periodic_pending;
NMDeviceConnectivityHandle *handle; NMDeviceConnectivityHandle *handle;
guint old_interval = priv->concheck_p_cur_interval; guint old_interval = priv->concheck_x[IS_IPv4].p_cur_interval;
any_periodic_pending = FALSE; any_periodic_pending = FALSE;
c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) { c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) {
if (handle->addr_family != addr_family)
continue;
if (handle->is_periodic_bump) { if (handle->is_periodic_bump) {
handle->is_periodic_bump = FALSE; handle->is_periodic_bump = FALSE;
handle->is_periodic_bump_on_complete = FALSE; handle->is_periodic_bump_on_complete = FALSE;
@@ -2622,7 +2643,7 @@ concheck_periodic_schedule_set (NMDevice *self,
/* we reached a timeout to schedule a new periodic request, however we still /* we reached a timeout to schedule a new periodic request, however we still
* have period requests pending that didn't complete yet. We need to bump the * have period requests pending that didn't complete yet. We need to bump the
* interval already. */ * interval already. */
priv->concheck_p_cur_interval = NM_MIN (old_interval * 2, priv->concheck_p_max_interval); priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (old_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval);
} }
/* we just reached a timeout. The expected expiry (exp_expiry) should be /* we just reached a timeout. The expected expiry (exp_expiry) should be
@@ -2630,13 +2651,13 @@ concheck_periodic_schedule_set (NMDevice *self,
* *
* We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */ * We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */
nm_utils_get_monotonic_timestamp_ns_cached (&now_ns); nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
exp_expiry = priv->concheck_p_cur_basetime_ns + (old_interval * NM_UTILS_NS_PER_SECOND); exp_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_interval * NM_UTILS_NS_PER_SECOND);
new_expiry = exp_expiry + (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); new_expiry = exp_expiry + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND);
tdiff = NM_MAX (new_expiry - now_ns, 0); tdiff = NM_MAX (new_expiry - now_ns, 0);
priv->concheck_p_cur_basetime_ns = (now_ns + tdiff) - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); priv->concheck_x[IS_IPv4].p_cur_basetime_ns = (now_ns + tdiff) - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND);
if (concheck_periodic_schedule_do (self, now_ns)) { if (concheck_periodic_schedule_do (self, addr_family, now_ns)) {
handle = concheck_start (self, NULL, NULL, TRUE); handle = concheck_start (self, addr_family, NULL, NULL, TRUE);
if (old_interval != priv->concheck_p_cur_interval) { if (old_interval != priv->concheck_x[IS_IPv4].p_cur_interval) {
/* we just bumped the interval already when scheduling this check. /* we just bumped the interval already when scheduling this check.
* When the handle returns, don't bump a second time. * When the handle returns, don't bump a second time.
* *
@@ -2651,13 +2672,13 @@ concheck_periodic_schedule_set (NMDevice *self,
/* we just got an event that we lost connectivity (that is, concheck returned). We reset /* we just got an event that we lost connectivity (that is, concheck returned). We reset
* the interval to min/max or increase the probe interval (bump). */ * the interval to min/max or increase the probe interval (bump). */
case CONCHECK_SCHEDULE_RETURNED_MIN: case CONCHECK_SCHEDULE_RETURNED_MIN:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL); priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL);
break; break;
case CONCHECK_SCHEDULE_RETURNED_MAX: case CONCHECK_SCHEDULE_RETURNED_MAX:
priv->concheck_p_cur_interval = priv->concheck_p_max_interval; priv->concheck_x[IS_IPv4].p_cur_interval = priv->concheck_x[IS_IPv4].p_max_interval;
break; break;
case CONCHECK_SCHEDULE_RETURNED_BUMP: case CONCHECK_SCHEDULE_RETURNED_BUMP:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_cur_interval * 2, priv->concheck_p_max_interval); priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_cur_interval * 2, priv->concheck_x[IS_IPv4].p_max_interval);
break; break;
} }
@@ -2667,38 +2688,40 @@ concheck_periodic_schedule_set (NMDevice *self,
* last check, instead of counting from now. The reason is that we want that the times * last check, instead of counting from now. The reason is that we want that the times
* when we schedule checks be at precise intervals, without including the time it took for * when we schedule checks be at precise intervals, without including the time it took for
* the connectivity check. */ * the connectivity check. */
new_expiry = priv->concheck_p_cur_basetime_ns + (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); new_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND);
tdiff = NM_MAX (new_expiry - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns), 0); tdiff = NM_MAX (new_expiry - nm_utils_get_monotonic_timestamp_ns_cached (&now_ns), 0);
priv->concheck_p_cur_basetime_ns = now_ns + tdiff - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND); priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns + tdiff - (priv->concheck_x[IS_IPv4].p_cur_interval * NM_UTILS_NS_PER_SECOND);
concheck_periodic_schedule_do (self, now_ns); concheck_periodic_schedule_do (self, addr_family, now_ns);
} }
static void static void
concheck_update_interval (NMDevice *self, gboolean check_now) concheck_update_interval (NMDevice *self, int addr_family, gboolean check_now)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
guint new_interval; guint new_interval;
const gboolean IS_IPv4 = (addr_family == AF_INET);
new_interval = nm_connectivity_get_interval (concheck_get_mgr (self)); new_interval = nm_connectivity_get_interval (concheck_get_mgr (self));
new_interval = NM_MIN (new_interval, 7 *24 * 3600); new_interval = NM_MIN (new_interval, 7 *24 * 3600);
if (new_interval != priv->concheck_p_max_interval) { if (new_interval != priv->concheck_x[IS_IPv4].p_max_interval) {
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: set interval to %u seconds", new_interval); _LOGT (LOGD_CONCHECK, "connectivity: periodic-check: set interval to %u seconds", new_interval);
priv->concheck_p_max_interval = new_interval; priv->concheck_x[IS_IPv4].p_max_interval = new_interval;
} }
if (!new_interval) { if (!new_interval) {
/* this will cancel any potentially pending timeout because max-interval is zero. /* this will cancel any potentially pending timeout because max-interval is zero.
* But it logs a nice message... */ * But it logs a nice message... */
concheck_periodic_schedule_do (self, 0); concheck_periodic_schedule_do (self, addr_family, 0);
/* also update the fake connectivity state. */ /* also update the fake connectivity state. */
concheck_update_state (self, NM_CONNECTIVITY_FAKE, TRUE); concheck_update_state (self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
return; return;
} }
concheck_periodic_schedule_set (self, concheck_periodic_schedule_set (self,
addr_family,
check_now check_now
? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART ? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART
: CONCHECK_SCHEDULE_UPDATE_INTERVAL); : CONCHECK_SCHEDULE_UPDATE_INTERVAL);
@@ -2707,13 +2730,16 @@ concheck_update_interval (NMDevice *self, gboolean check_now)
void void
nm_device_check_connectivity_update_interval (NMDevice *self) nm_device_check_connectivity_update_interval (NMDevice *self)
{ {
concheck_update_interval (self, FALSE); concheck_update_interval (self, AF_INET, FALSE);
concheck_update_interval (self, AF_INET6, FALSE);
} }
static void static void
concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow_periodic_bump) concheck_update_state (NMDevice *self, int addr_family,
NMConnectivityState state, gboolean allow_periodic_bump)
{ {
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const gboolean IS_IPv4 = (addr_family == AF_INET);
/* @state is a result of the connectivity check. We only expect a precise /* @state is a result of the connectivity check. We only expect a precise
* number of possible values. */ * number of possible values. */
@@ -2726,7 +2752,7 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
if (state == NM_CONNECTIVITY_ERROR) { if (state == NM_CONNECTIVITY_ERROR) {
/* on error, we don't change the current connectivity state, /* on error, we don't change the current connectivity state,
* except making UNKNOWN to NONE. */ * except making UNKNOWN to NONE. */
state = priv->connectivity_state; state = priv->concheck_x[IS_IPv4].state;
if (state == NM_CONNECTIVITY_UNKNOWN) if (state == NM_CONNECTIVITY_UNKNOWN)
state = NM_CONNECTIVITY_NONE; state = NM_CONNECTIVITY_NONE;
} else if (state == NM_CONNECTIVITY_FAKE) { } else if (state == NM_CONNECTIVITY_FAKE) {
@@ -2745,11 +2771,11 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
state = NM_CONNECTIVITY_NONE; state = NM_CONNECTIVITY_NONE;
} }
if (priv->connectivity_state == state) { if (priv->concheck_x[IS_IPv4].state == state) {
/* we got a connectivty update, but the state didn't change. If we were probing, /* we got a connectivty update, but the state didn't change. If we were probing,
* we bump the probe frequency. */ * we bump the probe frequency. */
if (allow_periodic_bump) if (allow_periodic_bump)
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP);
return; return;
} }
/* we need to update the probe interval before emitting signals. Emitting /* we need to update the probe interval before emitting signals. Emitting
@@ -2758,20 +2784,20 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
if (state == NM_CONNECTIVITY_FULL) { if (state == NM_CONNECTIVITY_FULL) {
/* we reached full connectivity state. Stop probing by setting the /* we reached full connectivity state. Stop probing by setting the
* interval to the max. */ * interval to the max. */
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MAX); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_MAX);
} else if (priv->connectivity_state == NM_CONNECTIVITY_FULL) { } else if (priv->concheck_x[IS_IPv4].state == NM_CONNECTIVITY_FULL) {
/* we are about to loose connectivity. (re)start probing by setting /* we are about to loose connectivity. (re)start probing by setting
* the timeout interval to the min. */ * the timeout interval to the min. */
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MIN); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_MIN);
} else { } else {
if (allow_periodic_bump) if (allow_periodic_bump)
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_BUMP); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_BUMP);
} }
_LOGD (LOGD_CONCHECK, "connectivity state changed from %s to %s", _LOGD (LOGD_CONCHECK, "connectivity state changed from %s to %s",
nm_connectivity_state_to_string (priv->connectivity_state), nm_connectivity_state_to_string (priv->concheck_x[IS_IPv4].state),
nm_connectivity_state_to_string (state)); nm_connectivity_state_to_string (state));
priv->connectivity_state = state; priv->concheck_x[IS_IPv4].state = state;
_notify (self, PROP_CONNECTIVITY); _notify (self, PROP_CONNECTIVITY);
g_signal_emit (self, signals[CONNECTIVITY_CHANGED], 0); g_signal_emit (self, signals[CONNECTIVITY_CHANGED], 0);
@@ -2788,9 +2814,10 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
} }
static void static void
concheck_handle_complete (NMDeviceConnectivityHandle *handle, concheck_handle_complete (NMDeviceConnectivityHandle *handle, GError *error)
GError *error)
{ {
const gboolean IS_IPv4 = (handle->addr_family == AF_INET);
/* The moment we invoke the callback, we unlink it. It signals /* The moment we invoke the callback, we unlink it. It signals
* that @handle is handled -- as far as the callee of callback * that @handle is handled -- as far as the callee of callback
* is concerned. */ * is concerned. */
@@ -2802,7 +2829,7 @@ concheck_handle_complete (NMDeviceConnectivityHandle *handle,
if (handle->callback) { if (handle->callback) {
handle->callback (handle->self, handle->callback (handle->self,
handle, handle,
NM_DEVICE_GET_PRIVATE (handle->self)->connectivity_state, NM_DEVICE_GET_PRIVATE (handle->self)->concheck_x[IS_IPv4].state,
error, error,
handle->user_data); handle->user_data);
} }
@@ -2864,6 +2891,8 @@ concheck_cb (NMConnectivity *connectivity,
any_periodic_before = FALSE; any_periodic_before = FALSE;
any_periodic_after = FALSE; any_periodic_after = FALSE;
c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) {
if (other_handle->addr_family != handle->addr_family)
continue;
if (other_handle->is_periodic_bump_on_complete) { if (other_handle->is_periodic_bump_on_complete) {
if (other_handle->seq < seq) if (other_handle->seq < seq)
any_periodic_before = TRUE; any_periodic_before = TRUE;
@@ -2890,7 +2919,7 @@ concheck_cb (NMConnectivity *connectivity,
} }
/* first update the new state, and emit signals. */ /* first update the new state, and emit signals. */
concheck_update_state (self, state, allow_periodic_bump); concheck_update_state (self, handle->addr_family, state, allow_periodic_bump);
handle_is_alive = FALSE; handle_is_alive = FALSE;
@@ -2902,6 +2931,8 @@ concheck_cb (NMConnectivity *connectivity,
* @handle, as they are automatically obsoleted. */ * @handle, as they are automatically obsoleted. */
check_handles: check_handles:
c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) { c_list_for_each_entry (other_handle, &priv->concheck_lst_head, concheck_lst) {
if (other_handle->addr_family != handle->addr_family)
continue;
if (other_handle->seq >= seq) { if (other_handle->seq >= seq) {
/* it's not guaranteed that @handle is still in the list. It might already /* it's not guaranteed that @handle is still in the list. It might already
* be canceled while invoking callbacks for a previous other_handle. * be canceled while invoking callbacks for a previous other_handle.
@@ -2939,6 +2970,7 @@ check_handles:
static NMDeviceConnectivityHandle * static NMDeviceConnectivityHandle *
concheck_start (NMDevice *self, concheck_start (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback, NMDeviceConnectivityCallback callback,
gpointer user_data, gpointer user_data,
gboolean is_periodic) gboolean is_periodic)
@@ -2959,6 +2991,7 @@ concheck_start (NMDevice *self,
handle->is_periodic = is_periodic; handle->is_periodic = is_periodic;
handle->is_periodic_bump = is_periodic; handle->is_periodic_bump = is_periodic;
handle->is_periodic_bump_on_complete = is_periodic; handle->is_periodic_bump_on_complete = is_periodic;
handle->addr_family = addr_family;
c_list_link_tail (&priv->concheck_lst_head, &handle->concheck_lst); c_list_link_tail (&priv->concheck_lst_head, &handle->concheck_lst);
@@ -2967,6 +3000,7 @@ concheck_start (NMDevice *self,
is_periodic ? ", periodic-check" : ""); is_periodic ? ", periodic-check" : "");
handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self), handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self),
handle->addr_family,
nm_device_get_ip_ifindex (self), nm_device_get_ip_ifindex (self),
nm_device_get_ip_iface (self), nm_device_get_ip_iface (self),
concheck_cb, concheck_cb,
@@ -2976,6 +3010,7 @@ concheck_start (NMDevice *self,
NMDeviceConnectivityHandle * NMDeviceConnectivityHandle *
nm_device_check_connectivity (NMDevice *self, nm_device_check_connectivity (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback, NMDeviceConnectivityCallback callback,
gpointer user_data) gpointer user_data)
{ {
@@ -2984,8 +3019,8 @@ nm_device_check_connectivity (NMDevice *self,
if (!concheck_is_possible (self)) if (!concheck_is_possible (self))
return NULL; return NULL;
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_EXTERNAL); concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
handle = concheck_start (self, callback, user_data, FALSE); handle = concheck_start (self, addr_family, callback, user_data, FALSE);
return handle; return handle;
} }
@@ -3009,9 +3044,13 @@ nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle)
NMConnectivityState NMConnectivityState
nm_device_get_connectivity_state (NMDevice *self) nm_device_get_connectivity_state (NMDevice *self)
{ {
NMDevicePrivate *priv;
g_return_val_if_fail (NM_IS_DEVICE (self), NM_CONNECTIVITY_UNKNOWN); g_return_val_if_fail (NM_IS_DEVICE (self), NM_CONNECTIVITY_UNKNOWN);
return NM_DEVICE_GET_PRIVATE (self)->connectivity_state; priv = NM_DEVICE_GET_PRIVATE (self);
return NM_MAX (priv->concheck_x[0].state, priv->concheck_x[1].state);
} }
/*****************************************************************************/ /*****************************************************************************/
@@ -7083,7 +7122,7 @@ ip_config_merge_and_apply (NMDevice *self,
if (commit) { if (commit) {
gboolean v; gboolean v;
v = default_route_metric_penalty_detect (self); v = default_route_metric_penalty_detect (self, addr_family);
if (IS_IPv4) if (IS_IPv4)
priv->default_route_metric_penalty_ip4_has = v; priv->default_route_metric_penalty_ip4_has = v;
else else
@@ -14851,8 +14890,8 @@ _set_state_full (NMDevice *self,
if (ip_config_valid (old_state) && !ip_config_valid (state)) if (ip_config_valid (old_state) && !ip_config_valid (state))
notify_ip_properties (self); notify_ip_properties (self);
concheck_update_interval (self, concheck_update_interval (self, AF_INET, state == NM_DEVICE_STATE_ACTIVATED);
state == NM_DEVICE_STATE_ACTIVATED); concheck_update_interval (self, AF_INET6, state == NM_DEVICE_STATE_ACTIVATED);
/* Dispose of the cached activation request */ /* Dispose of the cached activation request */
if (req) if (req)
@@ -15816,7 +15855,8 @@ nm_device_init (NMDevice *self)
c_list_init (&self->devices_lst); c_list_init (&self->devices_lst);
c_list_init (&priv->slaves); c_list_init (&priv->slaves);
priv->connectivity_state = NM_CONNECTIVITY_UNKNOWN; priv->concheck_x[0].state = NM_CONNECTIVITY_UNKNOWN;
priv->concheck_x[1].state = NM_CONNECTIVITY_UNKNOWN;
nm_dbus_track_obj_path_init (&priv->parent_device, G_OBJECT (self), obj_properties[PROP_PARENT]); nm_dbus_track_obj_path_init (&priv->parent_device, G_OBJECT (self), obj_properties[PROP_PARENT]);
nm_dbus_track_obj_path_init (&priv->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]); nm_dbus_track_obj_path_init (&priv->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]);
@@ -16017,7 +16057,8 @@ dispose (GObject *object)
g_clear_object (&priv->lldp_listener); g_clear_object (&priv->lldp_listener);
} }
nm_clear_g_source (&priv->concheck_p_cur_id); nm_clear_g_source (&priv->concheck_x[0].p_cur_id);
nm_clear_g_source (&priv->concheck_x[1].p_cur_id);
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object); G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
@@ -16355,7 +16396,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_uint64 (value, priv->stats.rx_bytes); g_value_set_uint64 (value, priv->stats.rx_bytes);
break; break;
case PROP_CONNECTIVITY: case PROP_CONNECTIVITY:
g_value_set_uint (value, priv->connectivity_state); g_value_set_uint (value, nm_device_get_connectivity_state (self));
break; break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);

View File

@@ -818,6 +818,7 @@ typedef void (*NMDeviceConnectivityCallback) (NMDevice *self,
void nm_device_check_connectivity_update_interval (NMDevice *self); void nm_device_check_connectivity_update_interval (NMDevice *self);
NMDeviceConnectivityHandle *nm_device_check_connectivity (NMDevice *self, NMDeviceConnectivityHandle *nm_device_check_connectivity (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback, NMDeviceConnectivityCallback callback,
gpointer user_data); gpointer user_data);

View File

@@ -68,6 +68,7 @@ struct _NMConnectivityCheckHandle {
gpointer user_data; gpointer user_data;
char *ifspec; char *ifspec;
int addr_family;
#if WITH_CONCHECK #if WITH_CONCHECK
struct { struct {
@@ -145,9 +146,10 @@ NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECT
_nm_log (__level, _NMLOG2_DOMAIN, 0, \ _nm_log (__level, _NMLOG2_DOMAIN, 0, \
(cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \ (cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \
NULL, \ NULL, \
"connectivity: (%s) " \ "connectivity: (%s,AF_INET%s) " \
_NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \
(cb_data->ifspec ? &cb_data->ifspec[3] : "") \ (cb_data->ifspec ? &cb_data->ifspec[3] : ""), \
(cb_data->addr_family == AF_INET6 ? "6" : "") \
_NM_UTILS_MACRO_REST (__VA_ARGS__)); \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \
} \ } \
} G_STMT_END } G_STMT_END
@@ -572,6 +574,7 @@ do_curl_request (NMConnectivityCheckHandle *cb_data)
{ {
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (cb_data->self); NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (cb_data->self);
CURL *ehandle; CURL *ehandle;
long resolve;
ehandle = curl_easy_init (); ehandle = curl_easy_init ();
if (!ehandle) { if (!ehandle) {
@@ -579,6 +582,21 @@ do_curl_request (NMConnectivityCheckHandle *cb_data)
return; return;
} }
switch (cb_data->addr_family) {
case AF_INET:
resolve = CURL_IPRESOLVE_V4;
break;
case AF_INET6:
resolve = CURL_IPRESOLVE_V6;
break;
case AF_UNSPEC:
resolve = CURL_IPRESOLVE_WHATEVER;
break;
default:
resolve = CURL_IPRESOLVE_WHATEVER;
g_warn_if_reached ();
}
cb_data->concheck.response = g_strdup (priv->response); cb_data->concheck.response = g_strdup (priv->response);
cb_data->concheck.curl_ehandle = ehandle; cb_data->concheck.curl_ehandle = ehandle;
cb_data->concheck.request_headers = curl_slist_append (NULL, "Connection: close"); cb_data->concheck.request_headers = curl_slist_append (NULL, "Connection: close");
@@ -593,6 +611,7 @@ do_curl_request (NMConnectivityCheckHandle *cb_data)
curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->concheck.request_headers); curl_easy_setopt (ehandle, CURLOPT_HTTPHEADER, cb_data->concheck.request_headers);
curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec); curl_easy_setopt (ehandle, CURLOPT_INTERFACE, cb_data->ifspec);
curl_easy_setopt (ehandle, CURLOPT_RESOLVE, cb_data->concheck.hosts); curl_easy_setopt (ehandle, CURLOPT_RESOLVE, cb_data->concheck.hosts);
curl_easy_setopt (ehandle, CURLOPT_IPRESOLVE, resolve);
curl_multi_add_handle (priv->concheck.curl_mhandle, ehandle); curl_multi_add_handle (priv->concheck.curl_mhandle, ehandle);
} }
@@ -607,7 +626,7 @@ resolve_cb (GObject *object, GAsyncResult *res, gpointer user_data)
GVariant *addresses; GVariant *addresses;
gsize no_addresses; gsize no_addresses;
int ifindex; int ifindex;
int family; int addr_family;
GVariant *address = NULL; GVariant *address = NULL;
const guchar *address_buf; const guchar *address_buf;
gsize len = 0; gsize len = 0;
@@ -635,14 +654,13 @@ resolve_cb (GObject *object, GAsyncResult *res, gpointer user_data)
g_variant_unref (result); g_variant_unref (result);
for (i = 0; i < no_addresses; i++) { for (i = 0; i < no_addresses; i++) {
g_variant_get_child (addresses, i, "(ii@ay)", &ifindex, &family, &address); g_variant_get_child (addresses, i, "(ii@ay)", &ifindex, &addr_family, &address);
address_buf = g_variant_get_fixed_array (address, &len, 1); address_buf = g_variant_get_fixed_array (address, &len, 1);
if ( (family == AF_INET && len == sizeof (struct in_addr)) if ( (addr_family == AF_INET && len == sizeof (struct in_addr))
|| (family == AF_INET6 && len == sizeof (struct in6_addr))) { || (addr_family == AF_INET6 && len == sizeof (struct in6_addr))) {
inet_ntop (family, address_buf, str, sizeof (str)); inet_ntop (addr_family, address_buf, str, sizeof (str));
host = g_strdup_printf ("%s:%s:%s", priv->host, host = g_strdup_printf ("%s:%s:%s", priv->host, priv->port ?: "80", str);
priv->port ? priv->port : "80", str);
cb_data->concheck.hosts = curl_slist_append (cb_data->concheck.hosts, host); cb_data->concheck.hosts = curl_slist_append (cb_data->concheck.hosts, host);
_LOG2T ("adding '%s' to curl resolve list", host); _LOG2T ("adding '%s' to curl resolve list", host);
g_free (host); g_free (host);
@@ -685,7 +703,7 @@ resolved_proxy_created (GObject *object, GAsyncResult *res, gpointer user_data)
g_variant_new ("(isit)", g_variant_new ("(isit)",
cb_data->concheck.ifindex, cb_data->concheck.ifindex,
priv->host, priv->host,
(gint32) AF_UNSPEC, (gint32) cb_data->addr_family,
(guint64) SD_RESOLVED_DNS), (guint64) SD_RESOLVED_DNS),
G_DBUS_CALL_FLAGS_NONE, G_DBUS_CALL_FLAGS_NONE,
-1, -1,
@@ -699,6 +717,7 @@ resolved_proxy_created (GObject *object, GAsyncResult *res, gpointer user_data)
NMConnectivityCheckHandle * NMConnectivityCheckHandle *
nm_connectivity_check_start (NMConnectivity *self, nm_connectivity_check_start (NMConnectivity *self,
int addr_family,
int ifindex, int ifindex,
const char *iface, const char *iface,
NMConnectivityCheckCallback callback, NMConnectivityCheckCallback callback,
@@ -719,6 +738,7 @@ nm_connectivity_check_start (NMConnectivity *self,
cb_data->callback = callback; cb_data->callback = callback;
cb_data->user_data = user_data; cb_data->user_data = user_data;
cb_data->completed_state = NM_CONNECTIVITY_UNKNOWN; cb_data->completed_state = NM_CONNECTIVITY_UNKNOWN;
cb_data->addr_family = addr_family;
if (iface) if (iface)
cb_data->ifspec = g_strdup_printf ("if!%s", iface); cb_data->ifspec = g_strdup_printf ("if!%s", iface);

View File

@@ -58,6 +58,7 @@ typedef void (*NMConnectivityCheckCallback) (NMConnectivity *self,
gpointer user_data); gpointer user_data);
NMConnectivityCheckHandle *nm_connectivity_check_start (NMConnectivity *self, NMConnectivityCheckHandle *nm_connectivity_check_start (NMConnectivity *self,
int family,
int ifindex, int ifindex,
const char *iface, const char *iface,
NMConnectivityCheckCallback callback, NMConnectivityCheckCallback callback,

View File

@@ -2812,6 +2812,7 @@ device_realized (NMDevice *device,
static void static void
device_connectivity_changed (NMDevice *device, device_connectivity_changed (NMDevice *device,
GParamSpec *pspec,
NMManager *self) NMManager *self)
{ {
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -6041,6 +6042,12 @@ check_connectivity_auth_done_cb (NMAuthChain *chain,
c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) {
if (nm_device_check_connectivity (device, if (nm_device_check_connectivity (device,
AF_INET,
device_connectivity_done,
data))
data->remaining++;
if (nm_device_check_connectivity (device,
AF_INET6,
device_connectivity_done, device_connectivity_done,
data)) data))
data->remaining++; data->remaining++;