ifcfg-rh: handle DEVTIMEOUT property (rh #1171917)

If an ifcfg file has a DEVTIMEOUT property (and a DEVICE, and is
ONBOOT=yes), and the device is not present at startup, then wait up to
DEVTIMEOUT seconds for it to appear before declaring the connection
ready.

This allows for a hacky workaround to devices that take a bizarrely
long time to be probed.

(cherry picked from commit 62d870e1a6)
This commit is contained in:
Dan Winship 2014-12-19 10:34:19 -05:00
parent c5bca2fb90
commit ee20ebb0fb
3 changed files with 135 additions and 1 deletions

View file

@ -33,6 +33,8 @@
#include <nm-setting-pppoe.h>
#include <nm-setting-wireless-security.h>
#include <nm-setting-8021x.h>
#include <nm-platform.h>
#include <nm-logging.h>
#include "common.h"
#include "nm-config.h"
@ -63,6 +65,9 @@ typedef struct {
char *unmanaged_spec;
char *unrecognized_spec;
gulong devtimeout_link_changed_handler;
guint devtimeout_timeout_id;
} NMIfcfgConnectionPrivate;
enum {
@ -80,6 +85,97 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
static gboolean
devtimeout_ready (gpointer user_data)
{
NMIfcfgConnection *self = user_data;
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
priv->devtimeout_timeout_id = 0;
nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE);
return FALSE;
}
static void
link_changed (NMPlatform *platform, int ifindex, NMPlatformLink *link,
NMPlatformSignalChangeType change_type, NMPlatformReason reason,
NMConnection *self)
{
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
const char *ifname;
ifname = nm_connection_get_interface_name (self);
if (g_strcmp0 (link->name, ifname) != 0)
return;
/* Shouldn't happen, but... */
if (change_type == NM_PLATFORM_SIGNAL_REMOVED)
return;
nm_log_info (LOGD_SETTINGS, "Device %s appeared; connection '%s' now ready",
ifname, nm_connection_get_id (self));
g_signal_handler_disconnect (platform, priv->devtimeout_link_changed_handler);
priv->devtimeout_link_changed_handler = 0;
g_source_remove (priv->devtimeout_timeout_id);
/* Don't declare the connection ready right away, since NMManager may not have
* started processing the device yet.
*/
priv->devtimeout_timeout_id = g_idle_add (devtimeout_ready, self);
}
static gboolean
devtimeout_expired (gpointer user_data)
{
NMIfcfgConnection *self = user_data;
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
nm_log_info (LOGD_SETTINGS, "Device for connection '%s' did not appear before timeout",
nm_connection_get_id (NM_CONNECTION (self)));
g_signal_handler_disconnect (nm_platform_get (), priv->devtimeout_link_changed_handler);
priv->devtimeout_link_changed_handler = 0;
priv->devtimeout_timeout_id = 0;
nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE);
return FALSE;
}
static void
nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self)
{
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self);
NMSettingConnection *s_con;
const char *ifname;
guint devtimeout;
s_con = nm_connection_get_setting_connection (NM_CONNECTION (self));
if (!nm_setting_connection_get_autoconnect (s_con))
return;
ifname = nm_setting_connection_get_interface_name (s_con);
if (!ifname)
return;
devtimeout = devtimeout_from_file (nm_ifcfg_connection_get_path (self));
if (!devtimeout)
return;
if (nm_platform_link_get_ifindex (ifname) != 0)
return;
/* ONBOOT=yes, DEVICE and DEVTIMEOUT are set, but device is not present */
nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), FALSE);
nm_log_info (LOGD_SETTINGS, "Waiting %u seconds for %s to appear for connection '%s'",
devtimeout, ifname, nm_connection_get_id (NM_CONNECTION (self)));
priv->devtimeout_link_changed_handler =
g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED,
G_CALLBACK (link_changed), self);
priv->devtimeout_timeout_id = g_timeout_add_seconds (devtimeout, devtimeout_expired, self);
}
static void
files_changed_cb (NMInotifyHelper *ih,
struct inotify_event *evt,
@ -141,8 +237,10 @@ nm_ifcfg_connection_new (NMConnection *source,
update_unsaved,
error)) {
/* Set the path and start monitoring */
if (full_path)
if (full_path) {
nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (object), full_path);
nm_ifcfg_connection_check_devtimeout (NM_IFCFG_CONNECTION (object));
}
} else
g_clear_object (&object);
@ -368,8 +466,20 @@ get_property (GObject *object, guint prop_id,
static void
dispose (GObject *object)
{
NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object);
path_watch_stop (NM_IFCFG_CONNECTION (object));
if (priv->devtimeout_link_changed_handler) {
g_signal_handler_disconnect (nm_platform_get (),
priv->devtimeout_link_changed_handler);
priv->devtimeout_link_changed_handler = 0;
}
if (priv->devtimeout_timeout_id) {
g_source_remove (priv->devtimeout_timeout_id);
priv->devtimeout_timeout_id = 0;
}
G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->dispose (object);
}

View file

@ -4862,3 +4862,25 @@ connection_from_file_test (const char *filename,
NULL);
}
guint
devtimeout_from_file (const char *filename)
{
shvarFile *ifcfg;
char *devtimeout_str;
guint devtimeout;
g_return_val_if_fail (filename != NULL, 0);
ifcfg = svOpenFile (filename, NULL);
if (!ifcfg)
return 0;
devtimeout_str = svGetValue (ifcfg, "DEVTIMEOUT", FALSE);
if (devtimeout_str) {
devtimeout = nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0);
g_free (devtimeout_str);
} else
devtimeout = 0;
return devtimeout;
}

View file

@ -32,6 +32,8 @@ NMConnection *connection_from_file (const char *filename,
char *uuid_from_file (const char *filename);
guint devtimeout_from_file (const char *filename);
/* for test-ifcfg-rh */
NMConnection *connection_from_file_test (const char *filename,
const char *network_file,