chiark / gitweb /
networkd: netdev - reduce chance of race when receiving netdev's ifindex
authorTom Gundersen <teg@jklm.no>
Wed, 29 Jan 2014 20:24:44 +0000 (21:24 +0100)
committerTom Gundersen <teg@jklm.no>
Thu, 30 Jan 2014 13:30:39 +0000 (14:30 +0100)
When creating a new link, the kernel will not inform us about the new ifindex
in its ack. We have to listen for newly created devices and deduce the new
ifindex by matching on the ifname.

We used to do this by waiting for a new device from libudev, but that is asking
for trouble, as udev will happily rename the device before handing it to us.
Listen on rtnl instead, the chance of the name being changed before reaching us
is much smaller (if not nil).

Kernel patch in the works to make this unneccessary.

src/network/networkd-link.c
src/network/networkd-manager.c
src/network/networkd-netdev.c
src/network/networkd.h

index f021918311234aa0c3b038181de7305878ff7e13..363602e9623538effcb2d2d72e795db8f73f89f7 100644 (file)
@@ -96,7 +96,6 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
         Network *network;
         int r;
         uint64_t ifindex;
-        NetdevKind kind;
 
         assert(m);
         assert(device);
@@ -114,13 +113,6 @@ int link_add(Manager *m, struct udev_device *device, Link **ret) {
 
         *ret = link;
 
-        kind = netdev_kind_from_string(udev_device_get_devtype(device));
-        if (kind != _NETDEV_KIND_INVALID) {
-                r = netdev_set_link(m, kind, link);
-                if (r < 0 && r != -ENOENT)
-                        return r;
-        }
-
         r = network_get(m, device, &network);
         if (r < 0)
                 return r == -ENOENT ? 0 : r;
index 7b93c5b5e8ee3e8130afa0a845f0b3007dc83084..a007b0485f5616ef04f715d9766e209cd6a7ec37 100644 (file)
@@ -25,6 +25,7 @@
 #include "networkd.h"
 #include "libudev-private.h"
 #include "udev-util.h"
+#include "rtnl-util.h"
 #include "mkdir.h"
 
 const char* const network_dirs[] = {
@@ -244,15 +245,31 @@ int manager_udev_listen(Manager *m) {
 static int manager_rtnl_process_link(sd_rtnl *rtnl, sd_rtnl_message *message, void *userdata) {
         Manager *m = userdata;
         Link *link;
+        const char *name;
         uint64_t ifindex_64;
         int r, ifindex;
 
         r = sd_rtnl_message_link_get_ifindex(message, &ifindex);
-        if (r < 0) {
+        if (r < 0 || ifindex <= 0) {
                 log_debug("received RTM_NEWLINK message without valid ifindex");
                 return 0;
         }
 
+        r = rtnl_message_link_get_ifname(message, &name);
+        if (r < 0)
+                log_debug("received RTM_NEWLINK message without valid IFLA_IFNAME");
+        else {
+                Netdev *netdev;
+
+                r = netdev_get(m, name, &netdev);
+                if (r >= 0) {
+                        r = netdev_set_ifindex(netdev, ifindex);
+                        if (r < 0)
+                                log_debug("could not set ifindex of netdev '%s' to %d: %s",
+                                          name, ifindex, strerror(-r));
+                }
+        }
+
         ifindex_64 = ifindex;
         link = hashmap_get(m->links, &ifindex_64);
         if (!link) {
index 1a6eebe1a71182ba1727b746fb123f9ba0eaef81..c0f3df5b66a5d1159ad49415676576e03ed94c5c 100644 (file)
@@ -98,7 +98,7 @@ static int netdev_enslave_ready(Netdev *netdev, Link* link, sd_rtnl_message_hand
                 return r;
         }
 
-        r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->link->ifindex);
+        r = sd_rtnl_message_append_u32(req, IFLA_MASTER, netdev->ifindex);
         if (r < 0) {
                 log_error_netdev(netdev,
                                  "Could not append IFLA_MASTER attribute: %s",
@@ -140,7 +140,7 @@ static int netdev_enter_ready(Netdev *netdev) {
 
 static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userdata) {
         Netdev *netdev = userdata;
-        int r;
+        int r, ifindex;
 
         assert(netdev->state != _NETDEV_STATE_INVALID);
 
@@ -152,6 +152,14 @@ static int netdev_create_handler(sd_rtnl *rtnl, sd_rtnl_message *m, void *userda
                 return 1;
         }
 
+        r = sd_rtnl_message_link_get_ifindex(m, &ifindex);
+        if (r < 0)
+                log_warning_netdev(netdev, "created netdev with unknown ifindex: %s", strerror(-r));
+        else {
+                log_info_netdev(netdev, "created netdev with ifindex %d", ifindex);
+                netdev_set_ifindex(netdev, ifindex);
+        }
+
         return 1;
 }
 
@@ -288,21 +296,18 @@ int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t callbac
         return 0;
 }
 
-int netdev_set_link(Manager *m, NetdevKind kind, Link *link) {
-        Netdev *netdev;
-        int r;
-
-        r = netdev_get(m, link->ifname, &netdev);
-        if (r < 0)
-                return r;
-
-        if (netdev->link && netdev->link != link)
-                return -EEXIST;
+int netdev_set_ifindex(Netdev *netdev, int ifindex) {
+        assert(netdev);
+        assert(ifindex > 0);
 
-        if (netdev->kind != kind)
-                return -EINVAL;
+        if (netdev->ifindex > 0) {
+                if (netdev->ifindex == ifindex)
+                        return 0;
+                else
+                        return -EEXIST;
+        }
 
-        netdev->link = link;
+        netdev->ifindex = ifindex;
 
         netdev_enter_ready(netdev);
 
index 01a8a7f681a448a261def0db5483b92f1c4f8b49..831a9cbdd951ff6a6b45e6b21a12ccb143741139 100644 (file)
@@ -77,7 +77,7 @@ struct Netdev {
 
         int vlanid;
 
-        Link *link;
+        int ifindex;
         NetdevState state;
 
         LIST_HEAD(netdev_enslave_callback, callbacks);
@@ -234,7 +234,7 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Netdev*, netdev_free);
 #define _cleanup_netdev_free_ _cleanup_(netdev_freep)
 
 int netdev_get(Manager *manager, const char *name, Netdev **ret);
-int netdev_set_link(Manager *m, NetdevKind kind, Link *link);
+int netdev_set_ifindex(Netdev *netdev, int ifindex);
 int netdev_enslave(Netdev *netdev, Link *link, sd_rtnl_message_handler_t cb);
 
 const char *netdev_kind_to_string(NetdevKind d) _const_;