chiark / gitweb /
networkd: link - flush all pending NEWLINK events before trying to match
authorTom Gundersen <teg@jklm.no>
Sat, 14 Jun 2014 16:52:46 +0000 (18:52 +0200)
committerTom Gundersen <teg@jklm.no>
Sat, 14 Jun 2014 17:01:46 +0000 (19:01 +0200)
We could still have an old interface name and/or mac address when libudev
tells us that the device is initialized, as the up-to-date info could still
be on its way from the kernel.

src/network/networkd-link.c

index 452fcd43c2203fa0c6cb7f4eafeefa245eed68e1..f496978cbae6e64744548f1d3dbc2300f61eac02 100644 (file)
@@ -1751,7 +1751,8 @@ static int link_configure(Link *link) {
         return link_enter_enslave(link);
 }
 
-int link_initialized(Link *link, struct udev_device *device) {
+static int link_initialized_and_synced(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
+        Link *link = userdata;
         Network *network;
         int r;
 
@@ -1762,12 +1763,9 @@ int link_initialized(Link *link, struct udev_device *device) {
         if (link->state != LINK_STATE_INITIALIZING)
                 return 0;
 
-        if (device)
-                link->udev_device = udev_device_ref(device);
+        log_debug_link(link, "link state is up-to-date");
 
-        log_debug_link(link, "udev initialized link");
-
-        r = network_get(link->manager, device, link->ifname, &link->mac, &network);
+        r = network_get(link->manager, link->udev_device, link->ifname, &link->mac, &network);
         if (r == -ENOENT) {
                 link_enter_unmanaged(link);
                 return 0;
@@ -1785,6 +1783,38 @@ int link_initialized(Link *link, struct udev_device *device) {
         return 0;
 }
 
+int link_initialized(Link *link, struct udev_device *device) {
+        _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->manager->rtnl);
+        assert(device);
+
+        if (link->state != LINK_STATE_INITIALIZING)
+                return 0;
+
+        log_debug_link(link, "udev initialized link");
+
+        link->udev_device = udev_device_ref(device);
+
+        /* udev has initialized the link, but we don't know if we have yet processed
+           the NEWLINK messages with the latest state. Do a GETLINK, when it returns
+           we know that the pending NEWLINKs have already been processed and that we
+           are up-to-date */
+
+        r = sd_rtnl_message_new_link(link->manager->rtnl, &req, RTM_GETLINK, link->ifindex);
+        if (r < 0)
+                return r;
+
+        r = sd_rtnl_call_async(link->manager->rtnl, req, link_initialized_and_synced, link, 0, NULL);
+        if (r < 0)
+                return r;
+
+        return 0;
+}
+
 int link_rtnl_process_address(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link = NULL;
@@ -1972,11 +2002,15 @@ int link_add(Manager *m, sd_rtnl_message *message, Link **ret) {
                         log_debug_link(link, "udev initializing link...");
                         return 0;
                 }
-        }
 
-        r = link_initialized(link, device);
-        if (r < 0)
-                return r;
+                r = link_initialized(link, device);
+                if (r < 0)
+                        return r;
+        } else {
+                r = link_initialized_and_synced(m->rtnl, NULL, link);
+                if (r < 0)
+                        return r;
+        }
 
         return 0;
 }