From fd41c989d5934d1319fd386ec4a020e6485b6617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pavel=20=C5=A0imerda?= Date: Thu, 17 Apr 2014 14:57:55 +0200 Subject: [PATCH] platform: fix software device handling when announcing links The handling for announcing links was broken resulting in duplicate link-added signals from platform. Co-Authored-By: Thomas Haller Signed-off-by: Thomas Haller --- src/platform/nm-linux-platform.c | 54 ++++++++++++++++++-------------- src/platform/tests/test-link.c | 9 ++++++ 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a9e5eae4b9..6aa8b650e2 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3594,38 +3594,40 @@ udev_device_added (NMPlatform *platform, auto_nl_object struct rtnl_link *rtnllink = NULL; const char *ifname; int ifindex; - gboolean is_changed; + gboolean was_announceable = FALSE; ifname = g_udev_device_get_name (udev_device); if (!ifname) { - debug ("failed to get device's interface"); + debug ("udev-add: failed to get device's interface"); return; } if (g_udev_device_get_property (udev_device, "IFINDEX")) ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); else { - warning ("(%s): failed to get device's ifindex", ifname); + warning ("(%s): udev-add: failed to get device's ifindex", ifname); + return; + } + if (ifindex <= 0) { + warning ("(%s): udev-add: retrieved invalid IFINDEX=%d", ifname, ifindex); return; } if (!g_udev_device_get_sysfs_path (udev_device)) { - debug ("(%s): couldn't determine device path; ignoring...", ifname); + debug ("(%s): udev-add: couldn't determine device path; ignoring...", ifname); return; } - is_changed = g_hash_table_lookup_extended (priv->udev_devices, GINT_TO_POINTER (ifindex), NULL, NULL); + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + if (rtnllink) + was_announceable = link_is_announceable (platform, rtnllink); + g_hash_table_insert (priv->udev_devices, GINT_TO_POINTER (ifindex), g_object_ref (udev_device)); - /* Don't announce devices that have not yet been discovered via Netlink. */ - rtnllink = rtnl_link_get (priv->link_cache, ifindex); - if (!rtnllink) { - debug ("%s: not found in link cache, ignoring...", ifname); - return; - } - - announce_object (platform, (struct nl_object *) rtnllink, is_changed ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); + /* Announce devices only if they also have been discovered via Netlink. */ + if (rtnllink && link_is_announceable (platform, rtnllink)) + announce_object (platform, (struct nl_object *) rtnllink, was_announceable ? NM_PLATFORM_SIGNAL_CHANGED : NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_REASON_EXTERNAL); } static void @@ -3633,12 +3635,13 @@ udev_device_removed (NMPlatform *platform, GUdevDevice *udev_device) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + auto_nl_object struct rtnl_link *rtnllink = NULL; int ifindex = 0; + gboolean was_announceable = FALSE; - if (g_udev_device_get_property (udev_device, "IFINDEX")) { + if (g_udev_device_get_property (udev_device, "IFINDEX")) ifindex = g_udev_device_get_property_as_int (udev_device, "IFINDEX"); - g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex)); - } else { + else { GHashTableIter iter; gpointer key, value; @@ -3650,19 +3653,24 @@ udev_device_removed (NMPlatform *platform, while (g_hash_table_iter_next (&iter, &key, &value)) { if ((GUdevDevice *)value == udev_device) { ifindex = GPOINTER_TO_INT (key); - g_hash_table_iter_remove (&iter); break; } } } - /* Announce device removal if it's still in the Netlink cache. */ - if (ifindex) { - auto_nl_object struct rtnl_link *device = rtnl_link_get (priv->link_cache, ifindex); + debug ("udev-remove: IFINDEX=%d", ifindex); + if (ifindex <= 0) + return; - if (device) - announce_object (platform, (struct nl_object *) device, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL); - } + rtnllink = rtnl_link_get (priv->link_cache, ifindex); + if (rtnllink) + was_announceable = link_is_announceable (platform, rtnllink); + + g_hash_table_remove (priv->udev_devices, GINT_TO_POINTER (ifindex)); + + /* Announce device removal if it is no longer announceable. */ + if (was_announceable && !link_is_announceable (platform, rtnllink)) + announce_object (platform, (struct nl_object *) rtnllink, NM_PLATFORM_SIGNAL_REMOVED, NM_PLATFORM_REASON_EXTERNAL); } static void diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c index b7c14aad9b..73c260c4ca 100644 --- a/src/platform/tests/test-link.c +++ b/src/platform/tests/test-link.c @@ -461,9 +461,11 @@ test_internal (void) static void test_external (void) { + NMPlatformLink link; SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME); SignalData *link_changed, *link_removed; int ifindex; + gboolean success; run_command ("ip link add %s type %s", DEVICE_NAME, "dummy"); wait_signal (link_added); @@ -476,6 +478,13 @@ test_external (void) link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex); link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex); + success = nm_platform_link_get (ifindex, &link); + g_assert (success); + if (!link.driver) { + /* we still lack the notification via UDEV. Expect another link changed signal. */ + wait_signal (link_changed); + } + /* Up/connected/arp */ g_assert (!nm_platform_link_is_up (ifindex)); g_assert (!nm_platform_link_is_connected (ifindex));