summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2015-07-01 13:42:41 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2015-07-01 13:42:41 +0200
commite86f8354a7aa5f8ba95b319f54f70e3e8aa9dbb7 (patch)
tree12abf34d4c6b18c212e737cc59dd915660b5cff3
parente3348b46bd0efbd23c0448a0c2ae367cee658d2c (diff)
downloadNetworkManager-e86f8354a7aa5f8ba95b319f54f70e3e8aa9dbb7.tar.gz
device: restart ping process when it exits with an error
When ping is launched to check the connectivity to the gateway it may return earlier than the given timeout in case of error. When this happens we need to respawn it until the timeout is reached. While at it, increase maximum timeout value to 600 seconds. https://bugzilla.redhat.com/show_bug.cgi?id=1128581
-rw-r--r--libnm-core/nm-setting-connection.c2
-rw-r--r--src/devices/nm-device.c124
2 files changed, 85 insertions, 41 deletions
diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c
index e4831aa173..03f97661ce 100644
--- a/libnm-core/nm-setting-connection.c
+++ b/libnm-core/nm-setting-connection.c
@@ -1663,7 +1663,7 @@ nm_setting_connection_class_init (NMSettingConnectionClass *setting_class)
g_object_class_install_property
(object_class, PROP_GATEWAY_PING_TIMEOUT,
g_param_spec_uint (NM_SETTING_CONNECTION_GATEWAY_PING_TIMEOUT, "", "",
- 0, 30, 0,
+ 0, 600, 0,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
G_PARAM_STATIC_STRINGS));
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index afe2fcd0a2..9a70bc6f53 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -76,6 +76,7 @@ _LOG_DECLARE_SELF (NMDevice);
static void impl_device_disconnect (NMDevice *self, DBusGMethodInvocation *context);
static void impl_device_delete (NMDevice *self, DBusGMethodInvocation *context);
static void nm_device_update_metered (NMDevice *self);
+static void ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data);
#include "nm-device-glue.h"
@@ -172,6 +173,9 @@ typedef struct {
guint timeout;
guint watch;
GPid pid;
+ const char *binary;
+ const char *address;
+ guint deadline;
} PingInfo;
typedef struct {
@@ -6649,19 +6653,67 @@ ip_check_gw_ping_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->gw_ping.watch) {
- g_source_remove (priv->gw_ping.watch);
- priv->gw_ping.watch = 0;
- }
- if (priv->gw_ping.timeout) {
- g_source_remove (priv->gw_ping.timeout);
- priv->gw_ping.timeout = 0;
- }
+ nm_clear_g_source (&priv->gw_ping.watch);
+ nm_clear_g_source (&priv->gw_ping.timeout);
if (priv->gw_ping.pid) {
nm_utils_kill_child_async (priv->gw_ping.pid, SIGTERM, priv->gw_ping.log_domain, "ping", 1000, NULL, NULL);
priv->gw_ping.pid = 0;
}
+
+ g_clear_pointer (&priv->gw_ping.binary, g_free);
+ g_clear_pointer (&priv->gw_ping.address, g_free);
+}
+
+static gboolean
+spawn_ping (NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ gs_free char *str_timeout;
+ gs_free char *tmp_str;
+ const char *args[] = { priv->gw_ping.binary, "-I", nm_device_get_ip_iface (self),
+ "-c", "1", "-w", NULL, priv->gw_ping.address, NULL };
+ gs_free_error GError *error = NULL;
+ gboolean ret;
+
+ args[6] = str_timeout = g_strdup_printf ("%u", priv->gw_ping.deadline);
+ tmp_str = g_strjoinv (" ", (gchar **) args);
+ _LOGD (priv->gw_ping.log_domain, "ping: running '%s'", tmp_str);
+
+ ret = g_spawn_async ("/",
+ (gchar **) args,
+ NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ NULL,
+ NULL,
+ &priv->gw_ping.pid,
+ &error);
+
+ if (!ret) {
+ _LOGW (priv->gw_ping.log_domain, "ping: could not spawn %s: %s",
+ priv->gw_ping.binary, error->message);
+ }
+
+ return ret;
+}
+
+static gboolean
+respawn_ping_cb (gpointer user_data)
+{
+ NMDevice *self = NM_DEVICE (user_data);
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ priv->gw_ping.watch = 0;
+
+ if (spawn_ping (self)) {
+ priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid,
+ ip_check_ping_watch_cb, self);
+ } else {
+ ip_check_gw_ping_cleanup (self);
+ ip_check_pre_up (self);
+ }
+
+ return FALSE;
}
static void
@@ -6670,6 +6722,7 @@ ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data)
NMDevice *self = NM_DEVICE (user_data);
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMLogDomain log_domain = priv->gw_ping.log_domain;
+ gboolean success = FALSE;
if (!priv->gw_ping.watch)
return;
@@ -6677,18 +6730,25 @@ ip_check_ping_watch_cb (GPid pid, gint status, gpointer user_data)
priv->gw_ping.pid = 0;
if (WIFEXITED (status)) {
- if (WEXITSTATUS (status) == 0)
+ if (WEXITSTATUS (status) == 0) {
_LOGD (log_domain, "ping: gateway ping succeeded");
- else {
+ success = TRUE;
+ } else {
_LOGW (log_domain, "ping: gateway ping failed with error code %d",
WEXITSTATUS (status));
}
} else
_LOGW (log_domain, "ping: stopped unexpectedly with status %d", status);
- /* We've got connectivity, proceed to pre_up */
- ip_check_gw_ping_cleanup (self);
- ip_check_pre_up (self);
+ if (success) {
+ /* We've got connectivity, proceed to pre_up */
+ ip_check_gw_ping_cleanup (self);
+ ip_check_pre_up (self);
+ } else {
+ /* If ping exited with an error it may have returned early,
+ * wait 1 second and restart it */
+ priv->gw_ping.watch = g_timeout_add_seconds (1, respawn_ping_cb, self);
+ }
}
static gboolean
@@ -6707,46 +6767,30 @@ ip_check_ping_timeout_cb (gpointer user_data)
}
static gboolean
-spawn_ping (NMDevice *self,
+start_ping (NMDevice *self,
NMLogDomain log_domain,
const char *binary,
const char *address,
guint timeout)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- const char *args[] = { binary, "-I", nm_device_get_ip_iface (self), "-c", "1", "-w", NULL, address, NULL };
- GError *error = NULL;
- char *str_timeout;
- gs_free char *tmp_str = NULL;
- gboolean success;
g_return_val_if_fail (priv->gw_ping.watch == 0, FALSE);
g_return_val_if_fail (priv->gw_ping.timeout == 0, FALSE);
- args[6] = str_timeout = g_strdup_printf ("%u", timeout);
-
- _LOGD (log_domain, "ping: running '%s'",
- (tmp_str = g_strjoinv (" ", (gchar **) args)));
+ priv->gw_ping.log_domain = log_domain;
+ priv->gw_ping.address = g_strdup (address);
+ priv->gw_ping.binary = g_strdup (binary);
+ priv->gw_ping.deadline = timeout + 10; /* the proper termination is enforced by a timer */
- success = g_spawn_async ("/",
- (gchar **) args,
- NULL,
- G_SPAWN_DO_NOT_REAP_CHILD,
- NULL,
- NULL,
- &priv->gw_ping.pid,
- &error);
- if (success) {
- priv->gw_ping.log_domain = log_domain;
+ if (spawn_ping (self)) {
priv->gw_ping.watch = g_child_watch_add (priv->gw_ping.pid, ip_check_ping_watch_cb, self);
- priv->gw_ping.timeout = g_timeout_add_seconds (timeout + 1, ip_check_ping_timeout_cb, self);
- } else {
- _LOGW (log_domain, "ping: could not spawn %s: %s", binary, error->message);
- g_clear_error (&error);
+ priv->gw_ping.timeout = g_timeout_add_seconds (timeout, ip_check_ping_timeout_cb, self);
+ return TRUE;
}
- g_free (str_timeout);
- return success;
+ ip_check_gw_ping_cleanup (self);
+ return FALSE;
}
static void
@@ -6799,7 +6843,7 @@ nm_device_start_ip_check (NMDevice *self)
}
if (buf[0])
- spawn_ping (self, log_domain, ping_binary, buf, timeout);
+ start_ping (self, log_domain, ping_binary, buf, timeout);
/* If no ping was started, just advance to pre_up */
if (!priv->gw_ping.pid)