diff options
author | Dan Williams <dcbw@redhat.com> | 2013-08-04 22:08:48 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2013-08-06 16:36:51 -0500 |
commit | eba74843671b494700f9b108e68f422187f851c9 (patch) | |
tree | 665bf1fb5f2df9f35b0549fa4bbccd0aa63bc1aa | |
parent | 3c6d789c629f05e25179224f6900ad17d7d0aab2 (diff) | |
download | NetworkManager-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.c | 81 |
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; } |