diff --git a/src/devices/nm-device-tun.c b/src/devices/nm-device-tun.c index 0ed182c4d..3f3988a53 100644 --- a/src/devices/nm-device-tun.c +++ b/src/devices/nm-device-tun.c @@ -37,6 +37,7 @@ G_DEFINE_TYPE (NMDeviceTun, nm_device_tun, NM_TYPE_DEVICE_GENERIC) typedef struct { NMPlatformTunProperties props; + guint delay_tun_get_properties_id; } NMDeviceTunPrivate; enum { @@ -53,17 +54,15 @@ enum { }; static void -link_changed (NMDevice *device, NMPlatformLink *info) +reload_tun_properties (NMDeviceTun *device) { NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (device); GObject *object = G_OBJECT (device); NMPlatformTunProperties props; - NM_DEVICE_CLASS (nm_device_tun_parent_class)->link_changed (device, info); - - if (!nm_platform_tun_get_properties (nm_device_get_ifindex (device), &props)) { + if (!nm_platform_tun_get_properties (nm_device_get_ifindex (NM_DEVICE (device)), &props)) { nm_log_warn (LOGD_HW, "(%s): could not read tun properties", - nm_device_get_iface (device)); + nm_device_get_iface (NM_DEVICE (device))); return; } @@ -87,6 +86,27 @@ link_changed (NMDevice *device, NMPlatformLink *info) g_object_thaw_notify (object); } +static void +link_changed (NMDevice *device, NMPlatformLink *info) +{ + NM_DEVICE_CLASS (nm_device_tun_parent_class)->link_changed (device, info); + + reload_tun_properties (NM_DEVICE_TUN (device)); +} + +static gboolean +delay_tun_get_properties_cb (gpointer user_data) +{ + NMDeviceTun *self = user_data; + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (self); + + priv->delay_tun_get_properties_id = 0; + + reload_tun_properties (self); + + return G_SOURCE_REMOVE; +} + /**************************************************************/ NMDevice * @@ -109,11 +129,32 @@ nm_device_tun_init (NMDeviceTun *self) static void constructed (GObject *object) { + gboolean properties_read; NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (object); - nm_platform_tun_get_properties (nm_device_get_ifindex (NM_DEVICE (object)), &priv->props); + properties_read = nm_platform_tun_get_properties (nm_device_get_ifindex (NM_DEVICE (object)), &priv->props); G_OBJECT_CLASS (nm_device_tun_parent_class)->constructed (object); + + if (!properties_read) { + /* Error reading the tun properties. Maybe this was due to a race. Try again a bit later. */ + nm_log_dbg (LOGD_HW, "(%s): could not read tun properties (retry)", + nm_device_get_iface (NM_DEVICE (object))); + priv->delay_tun_get_properties_id = g_timeout_add_seconds (1, delay_tun_get_properties_cb, object); + } +} + +static void +dispose (GObject *object) +{ + NMDeviceTunPrivate *priv = NM_DEVICE_TUN_GET_PRIVATE (object); + + if (priv->delay_tun_get_properties_id) { + g_source_remove (priv->delay_tun_get_properties_id); + priv->delay_tun_get_properties_id = 0; + } + + G_OBJECT_CLASS (nm_device_tun_parent_class)->dispose (object); } static void @@ -158,6 +199,7 @@ nm_device_tun_class_init (NMDeviceTunClass *klass) object_class->constructed = constructed; object_class->get_property = get_property; + object_class->dispose = dispose; device_class->link_changed = link_changed; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 45f98ebbd..0a1dfac52 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -44,6 +44,8 @@ #include #include "nm-linux-platform.h" +#include "NetworkManagerUtils.h" +#include "nm-utils.h" #include "nm-logging.h" #include "wifi/wifi-utils.h" @@ -619,12 +621,23 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char return_type (NM_LINK_TYPE_MACVTAP, "macvtap"); else if (!strcmp (type, "tun")) { NMPlatformTunProperties props; + guint flags; - if ( nm_platform_tun_get_properties (rtnl_link_get_ifindex (rtnllink), &props) - && !strcmp (props.mode, "tap")) - return_type (NM_LINK_TYPE_TAP, "tap"); - else + if (nm_platform_tun_get_properties (rtnl_link_get_ifindex (rtnllink), &props)) { + if (!g_strcmp0 (props.mode, "tap")) + return_type (NM_LINK_TYPE_TAP, "tap"); + if (!g_strcmp0 (props.mode, "tun")) + return_type (NM_LINK_TYPE_TUN, "tun"); + } + flags = rtnl_link_get_flags (rtnllink); + + nm_log_dbg (LOGD_PLATFORM, "Failed to read tun properties for interface %d (link flags: %X)", + rtnl_link_get_ifindex (rtnllink), flags); + + /* try guessing the type using the link flags instead... */ + if (flags & IFF_POINTOPOINT) return_type (NM_LINK_TYPE_TUN, "tun"); + return_type (NM_LINK_TYPE_TAP, "tap"); } else if (!strcmp (type, "veth")) return_type (NM_LINK_TYPE_VETH, "veth"); else if (!strcmp (type, "vlan")) @@ -2006,45 +2019,62 @@ tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties * { const char *ifname; char *path, *val; - guint32 flags; + gboolean success = TRUE; + + g_return_val_if_fail (props, FALSE); + + memset (props, 0, sizeof (*props)); + props->owner = -1; + props->group = -1; ifname = nm_platform_link_get_name (ifindex); - if (!ifname) + if (!ifname || !nm_utils_iface_valid_name (ifname)) return FALSE; path = g_strdup_printf ("/sys/class/net/%s/owner", ifname); - val = nm_platform_sysctl_get (path, FALSE); + val = nm_platform_sysctl_get (path, TRUE); g_free (path); - if (!val) - return FALSE; - props->owner = strtoll (val, NULL, 10); - g_free (val); + if (val) { + props->owner = nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; + g_free (val); + } else + success = FALSE; path = g_strdup_printf ("/sys/class/net/%s/group", ifname); - val = nm_platform_sysctl_get (path, FALSE); + val = nm_platform_sysctl_get (path, TRUE); g_free (path); - if (!val) - return FALSE; - props->group = strtoll (val, NULL, 10); - g_free (val); + if (val) { + props->group = nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1); + if (errno) + success = FALSE; + g_free (val); + } else + success = FALSE; path = g_strdup_printf ("/sys/class/net/%s/tun_flags", ifname); - val = nm_platform_sysctl_get (path, FALSE); + val = nm_platform_sysctl_get (path, TRUE); g_free (path); - if (!val) - return FALSE; - flags = strtoul (val, NULL, 16); - props->mode = ((flags & TUN_TYPE_MASK) == TUN_TUN_DEV) ? "tun" : "tap"; - props->no_pi = !!(flags & IFF_NO_PI); - props->vnet_hdr = !!(flags & IFF_VNET_HDR); -#ifdef IFF_MULTI_QUEUE - props->multi_queue = !!(flags & IFF_MULTI_QUEUE); -#else - props->multi_queue = FALSE; -#endif - g_free (val); + if (val) { + gint64 flags; - return TRUE; + flags = nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0); + if (!errno) { +#ifndef IFF_MULTI_QUEUE + const int IFF_MULTI_QUEUE = 0x0100; +#endif + props->mode = ((flags & TUN_TYPE_MASK) == TUN_TUN_DEV) ? "tun" : "tap"; + props->no_pi = !!(flags & IFF_NO_PI); + props->vnet_hdr = !!(flags & IFF_VNET_HDR); + props->multi_queue = !!(flags & IFF_MULTI_QUEUE); + } else + success = FALSE; + g_free (val); + } else + success = FALSE; + + return success; } static const struct nla_policy macvlan_info_policy[IFLA_MACVLAN_MAX + 1] = {