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_bump:1;
bool is_periodic_bump_on_complete:1;
int addr_family;
};
typedef struct {
@@ -555,24 +556,24 @@ typedef struct _NMDevicePrivate {
NMLldpListener *lldp_listener;
NMConnectivity *concheck_mgr;
CList concheck_lst_head;
struct {
/* if periodic checks are enabled, this is the source id for the next check. */
guint concheck_p_cur_id;
guint p_cur_id;
/* the currently configured max periodic interval. */
guint concheck_p_max_interval;
guint 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;
guint 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;
/* the timestamp, when we last scheduled the timer p_cur_id with current interval
* p_cur_interval. */
gint64 p_cur_basetime_ns;
NMConnectivityState connectivity_state;
CList concheck_lst_head;
NMConnectivityState state;
} concheck_x[2];
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 _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
default_route_metric_penalty_detect (NMDevice *self)
default_route_metric_penalty_detect (NMDevice *self, int addr_family)
{
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
* 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)))
return TRUE;
@@ -2448,23 +2453,35 @@ typedef enum {
} ConcheckScheduleMode;
static NMDeviceConnectivityHandle *concheck_start (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback,
gpointer user_data,
gboolean is_periodic);
static void concheck_periodic_schedule_set (NMDevice *self,
int addr_family,
ConcheckScheduleMode mode);
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");
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_PERIODIC);
concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_PERIODIC);
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
concheck_is_possible (NMDevice *self)
{
@@ -2483,17 +2500,18 @@ concheck_is_possible (NMDevice *self)
}
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);
gboolean periodic_check_disabled = FALSE;
gint64 expiry, tdiff;
const gboolean IS_IPv4 = (addr_family == AF_INET);
/* 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;
if (priv->concheck_p_max_interval == 0) {
if (priv->concheck_x[IS_IPv4].p_max_interval == 0) {
/* periodic checks are disabled */
goto out;
}
@@ -2502,22 +2520,23 @@ concheck_periodic_schedule_do (NMDevice *self, gint64 now_ns)
goto out;
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.
* Before calling concheck_periodic_schedule_do(), make sure that these properties are
* 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;
_LOGT (LOGD_CONCHECK, "connectivity: periodic-check: %sscheduled in %lld milliseconds (%u seconds interval)",
periodic_check_disabled ? "re-" : "",
(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,
concheck_periodic_timeout_cb,
priv->concheck_x[IS_IPv4].p_cur_id =
g_timeout_add (NM_MAX ((gint64) 0, tdiff) / NM_UTILS_NS_PER_MSEC,
IS_IPv4 ? concheck_ip4_periodic_timeout_cb : concheck_ip6_periodic_timeout_cb,
self);
return TRUE;
out:
@@ -2529,19 +2548,19 @@ out:
#define CONCHECK_P_PROBE_INTERVAL 1
static void
concheck_periodic_schedule_set (NMDevice *self,
ConcheckScheduleMode mode)
concheck_periodic_schedule_set (NMDevice *self, int addr_family, ConcheckScheduleMode mode)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
gint64 new_expiry, exp_expiry, cur_expiry, tdiff;
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. */
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
* another one... */
if (NM_IN_SET (mode, CONCHECK_SCHEDULE_UPDATE_INTERVAL,
@@ -2555,19 +2574,19 @@ concheck_periodic_schedule_set (NMDevice *self,
switch (mode) {
case CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART:
priv->concheck_p_cur_interval = NM_MIN (priv->concheck_p_max_interval, CONCHECK_P_PROBE_INTERVAL);
priv->concheck_p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
if (concheck_periodic_schedule_do (self, now_ns))
concheck_start (self, NULL, NULL, TRUE);
priv->concheck_x[IS_IPv4].p_cur_interval = NM_MIN (priv->concheck_x[IS_IPv4].p_max_interval, CONCHECK_P_PROBE_INTERVAL);
priv->concheck_x[IS_IPv4].p_cur_basetime_ns = nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
if (concheck_periodic_schedule_do (self, addr_family, now_ns))
concheck_start (self, addr_family, NULL, NULL, TRUE);
return;
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_p_cur_interval > 0);
nm_assert (priv->concheck_x[IS_IPv4].p_max_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,
* because we are probing, or because the previous max interval was shorter.
*
@@ -2576,17 +2595,17 @@ concheck_periodic_schedule_set (NMDevice *self,
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);
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) {
/* 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
* schedule a timeout in cur-interval in the future). */
priv->concheck_p_cur_basetime_ns = now_ns;
if (concheck_periodic_schedule_do (self, now_ns))
concheck_start (self, NULL, NULL, TRUE);
priv->concheck_x[IS_IPv4].p_cur_basetime_ns = now_ns;
if (concheck_periodic_schedule_do (self, addr_family, now_ns))
concheck_start (self, addr_family, NULL, NULL, TRUE);
} else {
/* we are reducing the max-interval to a shorter interval that we have currently
* 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
* expired. All we need to do, is reschedule the timer to expire sooner. The cur_basetime
* is unchanged. */
concheck_periodic_schedule_do (self, now_ns);
concheck_periodic_schedule_do (self, addr_family, now_ns);
}
return;
case CONCHECK_SCHEDULE_CHECK_EXTERNAL:
/* 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);
concheck_periodic_schedule_do (self, 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, addr_family, now_ns);
return;
case CONCHECK_SCHEDULE_CHECK_PERIODIC:
{
gboolean any_periodic_pending;
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;
c_list_for_each_entry (handle, &priv->concheck_lst_head, concheck_lst) {
if (handle->addr_family != addr_family)
continue;
if (handle->is_periodic_bump) {
handle->is_periodic_bump = 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
* have period requests pending that didn't complete yet. We need to bump the
* 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
@@ -2630,13 +2651,13 @@ concheck_periodic_schedule_set (NMDevice *self,
*
* We want to reschedule the timeout at exp_expiry (aka now) + cur_interval. */
nm_utils_get_monotonic_timestamp_ns_cached (&now_ns);
exp_expiry = priv->concheck_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);
exp_expiry = priv->concheck_x[IS_IPv4].p_cur_basetime_ns + (old_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);
priv->concheck_p_cur_basetime_ns = (now_ns + tdiff) - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND);
if (concheck_periodic_schedule_do (self, now_ns)) {
handle = concheck_start (self, NULL, NULL, TRUE);
if (old_interval != priv->concheck_p_cur_interval) {
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, addr_family, now_ns)) {
handle = concheck_start (self, addr_family, NULL, NULL, TRUE);
if (old_interval != priv->concheck_x[IS_IPv4].p_cur_interval) {
/* we just bumped the interval already when scheduling this check.
* 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
* the interval to min/max or increase the probe interval (bump). */
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;
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;
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;
}
@@ -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
* when we schedule checks be at precise intervals, without including the time it took for
* 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);
priv->concheck_p_cur_basetime_ns = now_ns + tdiff - (priv->concheck_p_cur_interval * NM_UTILS_NS_PER_SECOND);
concheck_periodic_schedule_do (self, now_ns);
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, addr_family, now_ns);
}
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);
guint new_interval;
const gboolean IS_IPv4 = (addr_family == AF_INET);
new_interval = nm_connectivity_get_interval (concheck_get_mgr (self));
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);
priv->concheck_p_max_interval = new_interval;
priv->concheck_x[IS_IPv4].p_max_interval = new_interval;
}
if (!new_interval) {
/* this will cancel any potentially pending timeout because max-interval is zero.
* 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. */
concheck_update_state (self, NM_CONNECTIVITY_FAKE, TRUE);
concheck_update_state (self, addr_family, NM_CONNECTIVITY_FAKE, TRUE);
return;
}
concheck_periodic_schedule_set (self,
addr_family,
check_now
? CONCHECK_SCHEDULE_UPDATE_INTERVAL_RESTART
: CONCHECK_SCHEDULE_UPDATE_INTERVAL);
@@ -2707,13 +2730,16 @@ concheck_update_interval (NMDevice *self, gboolean check_now)
void
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
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);
const gboolean IS_IPv4 = (addr_family == AF_INET);
/* @state is a result of the connectivity check. We only expect a precise
* number of possible values. */
@@ -2726,7 +2752,7 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
if (state == NM_CONNECTIVITY_ERROR) {
/* on error, we don't change the current connectivity state,
* except making UNKNOWN to NONE. */
state = priv->connectivity_state;
state = priv->concheck_x[IS_IPv4].state;
if (state == NM_CONNECTIVITY_UNKNOWN)
state = NM_CONNECTIVITY_NONE;
} else if (state == NM_CONNECTIVITY_FAKE) {
@@ -2745,11 +2771,11 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
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 bump the probe frequency. */
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;
}
/* 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) {
/* we reached full connectivity state. Stop probing by setting the
* interval to the max. */
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_RETURNED_MAX);
} else if (priv->connectivity_state == NM_CONNECTIVITY_FULL) {
concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_RETURNED_MAX);
} else if (priv->concheck_x[IS_IPv4].state == NM_CONNECTIVITY_FULL) {
/* we are about to loose connectivity. (re)start probing by setting
* 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 {
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",
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));
priv->connectivity_state = state;
priv->concheck_x[IS_IPv4].state = state;
_notify (self, PROP_CONNECTIVITY);
g_signal_emit (self, signals[CONNECTIVITY_CHANGED], 0);
@@ -2788,9 +2814,10 @@ concheck_update_state (NMDevice *self, NMConnectivityState state, gboolean allow
}
static void
concheck_handle_complete (NMDeviceConnectivityHandle *handle,
GError *error)
concheck_handle_complete (NMDeviceConnectivityHandle *handle, GError *error)
{
const gboolean IS_IPv4 = (handle->addr_family == AF_INET);
/* The moment we invoke the callback, we unlink it. It signals
* that @handle is handled -- as far as the callee of callback
* is concerned. */
@@ -2802,7 +2829,7 @@ concheck_handle_complete (NMDeviceConnectivityHandle *handle,
if (handle->callback) {
handle->callback (handle->self,
handle,
NM_DEVICE_GET_PRIVATE (handle->self)->connectivity_state,
NM_DEVICE_GET_PRIVATE (handle->self)->concheck_x[IS_IPv4].state,
error,
handle->user_data);
}
@@ -2864,6 +2891,8 @@ concheck_cb (NMConnectivity *connectivity,
any_periodic_before = FALSE;
any_periodic_after = FALSE;
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->seq < seq)
any_periodic_before = TRUE;
@@ -2890,7 +2919,7 @@ concheck_cb (NMConnectivity *connectivity,
}
/* 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;
@@ -2902,6 +2931,8 @@ concheck_cb (NMConnectivity *connectivity,
* @handle, as they are automatically obsoleted. */
check_handles:
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) {
/* it's not guaranteed that @handle is still in the list. It might already
* be canceled while invoking callbacks for a previous other_handle.
@@ -2939,6 +2970,7 @@ check_handles:
static NMDeviceConnectivityHandle *
concheck_start (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback,
gpointer user_data,
gboolean is_periodic)
@@ -2959,6 +2991,7 @@ concheck_start (NMDevice *self,
handle->is_periodic = is_periodic;
handle->is_periodic_bump = 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);
@@ -2967,6 +3000,7 @@ concheck_start (NMDevice *self,
is_periodic ? ", periodic-check" : "");
handle->c_handle = nm_connectivity_check_start (concheck_get_mgr (self),
handle->addr_family,
nm_device_get_ip_ifindex (self),
nm_device_get_ip_iface (self),
concheck_cb,
@@ -2976,6 +3010,7 @@ concheck_start (NMDevice *self,
NMDeviceConnectivityHandle *
nm_device_check_connectivity (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback,
gpointer user_data)
{
@@ -2984,8 +3019,8 @@ nm_device_check_connectivity (NMDevice *self,
if (!concheck_is_possible (self))
return NULL;
concheck_periodic_schedule_set (self, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
handle = concheck_start (self, callback, user_data, FALSE);
concheck_periodic_schedule_set (self, addr_family, CONCHECK_SCHEDULE_CHECK_EXTERNAL);
handle = concheck_start (self, addr_family, callback, user_data, FALSE);
return handle;
}
@@ -3009,9 +3044,13 @@ nm_device_check_connectivity_cancel (NMDeviceConnectivityHandle *handle)
NMConnectivityState
nm_device_get_connectivity_state (NMDevice *self)
{
NMDevicePrivate *priv;
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) {
gboolean v;
v = default_route_metric_penalty_detect (self);
v = default_route_metric_penalty_detect (self, addr_family);
if (IS_IPv4)
priv->default_route_metric_penalty_ip4_has = v;
else
@@ -14851,8 +14890,8 @@ _set_state_full (NMDevice *self,
if (ip_config_valid (old_state) && !ip_config_valid (state))
notify_ip_properties (self);
concheck_update_interval (self,
state == NM_DEVICE_STATE_ACTIVATED);
concheck_update_interval (self, AF_INET, state == NM_DEVICE_STATE_ACTIVATED);
concheck_update_interval (self, AF_INET6, state == NM_DEVICE_STATE_ACTIVATED);
/* Dispose of the cached activation request */
if (req)
@@ -15816,7 +15855,8 @@ nm_device_init (NMDevice *self)
c_list_init (&self->devices_lst);
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->act_request, G_OBJECT (self), obj_properties[PROP_ACTIVE_CONNECTION]);
@@ -16017,7 +16057,8 @@ dispose (GObject *object)
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);
@@ -16355,7 +16396,7 @@ get_property (GObject *object, guint prop_id,
g_value_set_uint64 (value, priv->stats.rx_bytes);
break;
case PROP_CONNECTIVITY:
g_value_set_uint (value, priv->connectivity_state);
g_value_set_uint (value, nm_device_get_connectivity_state (self));
break;
default:
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);
NMDeviceConnectivityHandle *nm_device_check_connectivity (NMDevice *self,
int addr_family,
NMDeviceConnectivityCallback callback,
gpointer user_data);

View File

@@ -68,6 +68,7 @@ struct _NMConnectivityCheckHandle {
gpointer user_data;
char *ifspec;
int addr_family;
#if WITH_CONCHECK
struct {
@@ -145,9 +146,10 @@ NM_DEFINE_SINGLETON_GETTER (NMConnectivity, nm_connectivity_get, NM_TYPE_CONNECT
_nm_log (__level, _NMLOG2_DOMAIN, 0, \
(cb_data->ifspec ? &cb_data->ifspec[3] : NULL), \
NULL, \
"connectivity: (%s) " \
"connectivity: (%s,AF_INET%s) " \
_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__)); \
} \
} G_STMT_END
@@ -572,6 +574,7 @@ do_curl_request (NMConnectivityCheckHandle *cb_data)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE (cb_data->self);
CURL *ehandle;
long resolve;
ehandle = curl_easy_init ();
if (!ehandle) {
@@ -579,6 +582,21 @@ do_curl_request (NMConnectivityCheckHandle *cb_data)
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.curl_ehandle = ehandle;
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_INTERFACE, cb_data->ifspec);
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);
}
@@ -607,7 +626,7 @@ resolve_cb (GObject *object, GAsyncResult *res, gpointer user_data)
GVariant *addresses;
gsize no_addresses;
int ifindex;
int family;
int addr_family;
GVariant *address = NULL;
const guchar *address_buf;
gsize len = 0;
@@ -635,14 +654,13 @@ resolve_cb (GObject *object, GAsyncResult *res, gpointer user_data)
g_variant_unref (result);
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);
if ( (family == AF_INET && len == sizeof (struct in_addr))
|| (family == AF_INET6 && len == sizeof (struct in6_addr))) {
inet_ntop (family, address_buf, str, sizeof (str));
host = g_strdup_printf ("%s:%s:%s", priv->host,
priv->port ? priv->port : "80", str);
if ( (addr_family == AF_INET && len == sizeof (struct in_addr))
|| (addr_family == AF_INET6 && len == sizeof (struct in6_addr))) {
inet_ntop (addr_family, address_buf, str, sizeof (str));
host = g_strdup_printf ("%s:%s:%s", priv->host, priv->port ?: "80", str);
cb_data->concheck.hosts = curl_slist_append (cb_data->concheck.hosts, host);
_LOG2T ("adding '%s' to curl resolve list", host);
g_free (host);
@@ -685,7 +703,7 @@ resolved_proxy_created (GObject *object, GAsyncResult *res, gpointer user_data)
g_variant_new ("(isit)",
cb_data->concheck.ifindex,
priv->host,
(gint32) AF_UNSPEC,
(gint32) cb_data->addr_family,
(guint64) SD_RESOLVED_DNS),
G_DBUS_CALL_FLAGS_NONE,
-1,
@@ -699,6 +717,7 @@ resolved_proxy_created (GObject *object, GAsyncResult *res, gpointer user_data)
NMConnectivityCheckHandle *
nm_connectivity_check_start (NMConnectivity *self,
int addr_family,
int ifindex,
const char *iface,
NMConnectivityCheckCallback callback,
@@ -719,6 +738,7 @@ nm_connectivity_check_start (NMConnectivity *self,
cb_data->callback = callback;
cb_data->user_data = user_data;
cb_data->completed_state = NM_CONNECTIVITY_UNKNOWN;
cb_data->addr_family = addr_family;
if (iface)
cb_data->ifspec = g_strdup_printf ("if!%s", iface);

View File

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

View File

@@ -2812,6 +2812,7 @@ device_realized (NMDevice *device,
static void
device_connectivity_changed (NMDevice *device,
GParamSpec *pspec,
NMManager *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) {
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,
data))
data->remaining++;