connectivity: Add a timeout option to connectivity checks

Adds an option in the connectivity section to change the timeout before
the interface is deemed "limited". Previously, it was hardcoded to
20 seconds, but for our usecase (failing over to cell modem if
hardwired ethernet drops), it's nice to be able to failover to another
interface more quickly.
This commit is contained in:
Mary Strodl 2024-06-12 14:20:21 -04:00 committed by Beniamino Galvani
parent 0d657af256
commit ed318e8774
10 changed files with 58 additions and 1 deletions

1
NEWS
View file

@ -9,6 +9,7 @@ the later release.
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
* Support matching a OVS system interface by MAC address.
* Add a timeout option to connectivity checking.
=============================================
NetworkManager-1.48

View file

@ -1480,6 +1480,12 @@ managed=1
set to 0 connectivity checking is disabled. If missing, the
default is 300 seconds.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>timeout</varname></term>
<listitem><para>Specified in seconds; controls how long
to wait for a response before connectivity is marked as
limited. If missing, the default is 20 seconds.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>response</varname></term>
<listitem><para>If set, controls what body content

View file

@ -62,6 +62,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_CONFIG_MAIN_FILE,
PROP_CONNECTIVITY_ENABLED,
PROP_CONNECTIVITY_URI,
PROP_CONNECTIVITY_INTERVAL,
PROP_CONNECTIVITY_TIMEOUT,
PROP_CONNECTIVITY_RESPONSE,
PROP_NO_AUTO_DEFAULT, );
@ -86,6 +87,7 @@ typedef struct {
char *uri;
char *response;
guint interval;
guint timeout;
} connectivity;
int autoconnect_retries_default;
@ -304,6 +306,14 @@ nm_config_data_get_connectivity_interval(const NMConfigData *self)
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.interval;
}
guint
nm_config_data_get_connectivity_timeout(const NMConfigData *self)
{
g_return_val_if_fail(self, 0);
return NM_CONFIG_DATA_GET_PRIVATE(self)->connectivity.timeout;
}
const char *
nm_config_data_get_connectivity_response(const NMConfigData *self)
{
@ -2006,6 +2016,8 @@ nm_config_data_diff(NMConfigData *old_data, NMConfigData *new_data)
!= nm_config_data_get_connectivity_enabled(new_data)
|| nm_config_data_get_connectivity_interval(old_data)
!= nm_config_data_get_connectivity_interval(new_data)
|| nm_config_data_get_connectivity_timeout(old_data)
!= nm_config_data_get_connectivity_timeout(new_data)
|| !nm_streq0(nm_config_data_get_connectivity_uri(old_data),
nm_config_data_get_connectivity_uri(new_data))
|| !nm_streq0(nm_config_data_get_connectivity_response(old_data),
@ -2079,6 +2091,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
case PROP_CONNECTIVITY_INTERVAL:
g_value_set_uint(value, nm_config_data_get_connectivity_interval(self));
break;
case PROP_CONNECTIVITY_TIMEOUT:
g_value_set_uint(value, nm_config_data_get_connectivity_timeout(self));
break;
case PROP_CONNECTIVITY_RESPONSE:
g_value_set_string(value, nm_config_data_get_connectivity_response(self));
break;
@ -2221,6 +2236,15 @@ constructed(GObject *object)
NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL);
g_free(str);
/* On missing or invalid config value, fallback to 20. */
str = g_key_file_get_string(priv->keyfile,
NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_TIMEOUT,
NULL);
priv->connectivity.timeout =
_nm_utils_ascii_str_to_int64(str, 10, 0, G_MAXUINT, NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT);
g_free(str);
priv->dns_mode = nm_strstrip(g_key_file_get_string(priv->keyfile,
NM_CONFIG_KEYFILE_GROUP_MAIN,
NM_CONFIG_KEYFILE_KEY_MAIN_DNS,
@ -2420,6 +2444,15 @@ nm_config_data_class_init(NMConfigDataClass *config_class)
0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_CONNECTIVITY_TIMEOUT] =
g_param_spec_uint(NM_CONFIG_DATA_CONNECTIVITY_TIMEOUT,
"",
"",
0,
G_MAXUINT,
0,
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
obj_properties[PROP_CONNECTIVITY_RESPONSE] =
g_param_spec_string(NM_CONFIG_DATA_CONNECTIVITY_RESPONSE,
"",

View file

@ -47,6 +47,7 @@ typedef enum {
#define NM_CONFIG_DATA_CONNECTIVITY_ENABLED "connectivity-enabled"
#define NM_CONFIG_DATA_CONNECTIVITY_URI "connectivity-uri"
#define NM_CONFIG_DATA_CONNECTIVITY_INTERVAL "connectivity-interval"
#define NM_CONFIG_DATA_CONNECTIVITY_TIMEOUT "connectivity-timeout"
#define NM_CONFIG_DATA_CONNECTIVITY_RESPONSE "connectivity-response"
#define NM_CONFIG_DATA_NO_AUTO_DEFAULT "no-auto-default"
#define NM_CONFIG_DATA_DNS_MODE "dns"
@ -172,6 +173,7 @@ char **nm_config_data_get_plugins(const NMConfigData *config_data, gboolean
gboolean nm_config_data_get_connectivity_enabled(const NMConfigData *config_data);
const char *nm_config_data_get_connectivity_uri(const NMConfigData *config_data);
guint nm_config_data_get_connectivity_interval(const NMConfigData *config_data);
guint nm_config_data_get_connectivity_timeout(const NMConfigData *config_data);
const char *nm_config_data_get_connectivity_response(const NMConfigData *config_data);
int nm_config_data_get_autoconnect_retries_default(const NMConfigData *config_data);

View file

@ -871,6 +871,7 @@ static const ConfigGroup config_groups[] = {
.group = NM_CONFIG_KEYFILE_GROUP_CONNECTIVITY,
.keys = NM_MAKE_STRV(NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_ENABLED,
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_INTERVAL,
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_TIMEOUT,
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_RESPONSE,
NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_URI, ),
},

View file

@ -28,6 +28,7 @@
#define NM_CONFIG_SIGNAL_CONFIG_CHANGED "config-changed"
#define NM_CONFIG_DEFAULT_CONNECTIVITY_INTERVAL 300
#define NM_CONFIG_DEFAULT_CONNECTIVITY_TIMEOUT 20
#define NM_CONFIG_DEFAULT_CONNECTIVITY_RESPONSE "NetworkManager is online" /* NOT LOCALIZED */
typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;

View file

@ -56,6 +56,7 @@ typedef struct {
char *host;
char *port;
char *response;
guint timeout;
} ConConfig;
struct _NMConnectivityCheckHandle {
@ -738,7 +739,9 @@ do_curl_request(NMConnectivityCheckHandle *cb_data, const char *hosts)
cb_data->concheck.curl_mhandle = mhandle;
cb_data->concheck.curl_ehandle = ehandle;
cb_data->concheck.request_headers = curl_slist_append(NULL, "Connection: close");
cb_data->timeout_source = nm_g_timeout_add_seconds_source(20, _timeout_cb, cb_data);
cb_data->timeout_source = nm_g_timeout_add_seconds_source(cb_data->concheck.con_config->timeout,
_timeout_cb,
cb_data);
curl_multi_setopt(mhandle, CURLMOPT_SOCKETFUNCTION, multi_socket_cb);
curl_multi_setopt(mhandle, CURLMOPT_SOCKETDATA, cb_data);
@ -1226,6 +1229,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
{
NMConnectivityPrivate *priv = NM_CONNECTIVITY_GET_PRIVATE(self);
guint interval;
guint new_timeout;
gboolean enabled;
gboolean changed = FALSE;
const char *cur_uri = priv->con_config ? priv->con_config->uri : NULL;
@ -1237,6 +1241,8 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
gs_free char *new_host = NULL;
gs_free char *new_port = NULL;
new_timeout = nm_config_data_get_connectivity_timeout(config_data);
new_uri = nm_config_data_get_connectivity_uri(config_data);
if (!nm_streq0(new_uri, cur_uri)) {
new_uri_valid = (new_uri && *new_uri);
@ -1277,6 +1283,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
changed = TRUE;
if (!priv->con_config || !nm_streq0(new_uri, priv->con_config->uri)
|| new_timeout != priv->con_config->timeout
|| !nm_streq0(new_response, priv->con_config->response)) {
if (!new_host_port) {
new_host = priv->con_config ? g_strdup(priv->con_config->host) : NULL;
@ -1290,6 +1297,7 @@ update_config(NMConnectivity *self, NMConfigData *config_data)
.response = g_strdup(new_response),
.host = g_steal_pointer(&new_host),
.port = g_steal_pointer(&new_port),
.timeout = new_timeout,
};
}
priv->uri_valid = new_uri_valid;

View file

@ -9,6 +9,7 @@ level=INFO
[connectivity]
uri=http://example.com
interval=100
timeout=42
response=Hello
[extra-section]

View file

@ -167,6 +167,9 @@ test_config_simple(void)
g_assert_cmpint(nm_config_data_get_connectivity_interval(nm_config_get_data_orig(config)),
==,
100);
g_assert_cmpint(nm_config_data_get_connectivity_timeout(nm_config_get_data_orig(config)),
==,
42);
plugins = nm_config_data_get_plugins(nm_config_get_data_orig(config), FALSE);
g_assert_cmpint(g_strv_length((char **) plugins), ==, 3);

View file

@ -44,6 +44,7 @@
#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_ENABLED "enabled"
#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_INTERVAL "interval"
#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_TIMEOUT "timeout"
#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_RESPONSE "response"
#define NM_CONFIG_KEYFILE_KEY_CONNECTIVITY_URI "uri"