summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-08-04 22:08:48 -0500
committerDan Williams <dcbw@redhat.com>2013-08-06 16:36:51 -0500
commiteba74843671b494700f9b108e68f422187f851c9 (patch)
tree665bf1fb5f2df9f35b0549fa4bbccd0aa63bc1aa
parent3c6d789c629f05e25179224f6900ad17d7d0aab2 (diff)
downloadNetworkManager-eba74843671b494700f9b108e68f422187f851c9.tar.gz
core: don't wait for udev to find created software devices
NM knows software devices it creates exist immediately, and it knows it can use them immediately instead of waiting for udev to find them. Ideally we'd wait for udev to find all devices, to allow tags and other rules to run, but when creating software devices they must currently be available for use immediately. Bridges and bonds are required to be IFF_UP before they can be activated (see their is_available() implementation). But during activation code paths, specifically in nm_manager_activate_connection(), the interface is created and immediately checked for availability to activate (since the creation was a result of the user requesting device activation). That availability check fails, because the device is not visible outside NMPlatform (because it hasn't been found by udev yet, because we haven't gotten back to the event loop) and thus nm_platform_link_is_up() fails, failing the availability check. Thus the device activation ends in error. What should really happen is that device activation shouldn't be synchronous; a new NMActiveConnection should be created for any activation request, which can then wait until all the resources it needs for activation are available (device found, master devices created, etc). That's going to take more work though.
-rw-r--r--src/platform/nm-linux-platform.c81
1 files changed, 66 insertions, 15 deletions
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 022bd5002c..901f3c0933 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -436,6 +436,51 @@ link_type_from_udev (NMPlatform *platform, struct rtnl_link *rtnllink, const cha
return_type (NM_LINK_TYPE_ETHERNET, "ethernet");
}
+static gboolean
+link_is_software (struct rtnl_link *link)
+{
+ const char *type = rtnl_link_get_type (link);
+
+ /* FIXME: replace somehow with NMLinkType or nm_platform_is_software(), but
+ * solve the infinite callstack problems that getting the type of a TUN/TAP
+ * device causes.
+ */
+ if (type == NULL)
+ return FALSE;
+
+ if (!strcmp (type, "dummy") ||
+ !strcmp (type, "gre") ||
+ !strcmp (type, "gretap") ||
+ !strcmp (type, "macvlan") ||
+ !strcmp (type, "macvtap") ||
+ !strcmp (type, "tun") ||
+ !strcmp (type, "veth") ||
+ !strcmp (type, "vlan") ||
+ !strcmp (type, "bridge") ||
+ !strcmp (type, "bond") ||
+ !strcmp (type, "team"))
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
+link_is_announcable (NMPlatform *platform, struct rtnl_link *rtnllink)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+
+ /* Software devices are always visible outside the platform */
+ if (link_is_software (rtnllink))
+ return TRUE;
+
+ /* Hardware devices must be found by udev so rules get run and tags set */
+ if (g_hash_table_lookup (priv->udev_devices,
+ GINT_TO_POINTER (rtnl_link_get_ifindex (rtnllink))))
+ return TRUE;
+
+ return FALSE;
+}
+
static NMLinkType
link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, const char **out_name)
{
@@ -787,19 +832,20 @@ announce_object (NMPlatform *platform, const struct nl_object *object, ObjectSta
case LINK:
{
NMPlatformLink device;
+ struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
- link_init (platform, &device, (struct rtnl_link *) object);
+ link_init (platform, &device, rtnl_link);
- /* Skip devices not yet discovered by udev. They will be announced
- * by udev_device_added(). This doesn't apply to removed devices, as
- * those come either from udev_device_removed(), event_notification()
- * or link_delete() which block the announcment themselves when
- * appropriate.
+ /* Skip hardware devices not yet discovered by udev. They will be
+ * announced by udev_device_added(). This doesn't apply to removed
+ * devices, as those come either from udev_device_removed(),
+ * event_notification() or link_delete() which block the announcment
+ * themselves when appropriate.
*/
switch (status) {
case ADDED:
case CHANGED:
- if (!device.driver)
+ if (!link_is_software (rtnl_link) && !device.driver)
return;
break;
default:
@@ -1058,9 +1104,7 @@ event_notification (struct nl_msg *msg, gpointer user_data)
* already removed and announced.
*/
if (event == RTM_DELLINK) {
- int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) object);
-
- if (!g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex)))
+ if (!link_is_announcable (platform, (struct rtnl_link *) object))
return NL_OK;
}
announce_object (platform, cached_object, REMOVED, NM_PLATFORM_REASON_EXTERNAL);
@@ -1185,10 +1229,10 @@ link_get_all (NMPlatform *platform)
struct nl_object *object;
for (object = nl_cache_get_first (priv->link_cache); object; object = nl_cache_get_next (object)) {
- int ifindex = rtnl_link_get_ifindex ((struct rtnl_link *) object);
+ struct rtnl_link *rtnl_link = (struct rtnl_link *) object;
- if (g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex))) {
- link_init (platform, &device, (struct rtnl_link *) object);
+ if (link_is_announcable (platform, rtnl_link)) {
+ link_init (platform, &device, rtnl_link);
g_array_append_val (links, device);
}
}
@@ -1243,7 +1287,13 @@ link_get (NMPlatform *platform, int ifindex)
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
auto_nl_object struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex);
- if (!rtnllink || !g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex))) {
+ if (!rtnllink) {
+ platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
+ return NULL;
+ }
+
+ /* physical interfaces must be found by udev before they can be used */
+ if (!link_is_announcable (platform, rtnllink)) {
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
return NULL;
}
@@ -1293,8 +1343,9 @@ static gboolean
link_delete (NMPlatform *platform, int ifindex)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ struct rtnl_link *rtnllink = rtnl_link_get (priv->link_cache, ifindex);
- if (!g_hash_table_lookup (priv->udev_devices, GINT_TO_POINTER (ifindex))) {
+ if (!rtnllink) {
platform->error = NM_PLATFORM_ERROR_NOT_FOUND;
return FALSE;
}