]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: simplify the logic of reading driver and permanent HW address
authorYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 26 Oct 2022 02:43:46 +0000 (11:43 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 31 Oct 2022 00:34:41 +0000 (09:34 +0900)
No functional changes, just refactoring and preparation for later
commits.

Note, `link->dev` should always exist when link state is initialized or
later.

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

index 0759fbd9eb1a5626c1454d3e4a123fddbb277df5..d3dafb245873ecbda1bd910afbbd5c97400b5bb6 100644 (file)
@@ -2028,15 +2028,17 @@ static int link_update_driver(Link *link, sd_netlink_message *message) {
         assert(message);
 
         /* Driver is already read. Assuming the driver is never changed. */
-        if (link->driver)
+        if (link->ethtool_driver_read)
                 return 0;
 
         /* When udevd is running, read the driver after the interface is initialized by udevd.
          * Otherwise, ethtool may not work correctly. See issue #22538.
          * When udevd is not running, read the value when the interface is detected. */
-        if (link->state != (udev_available() ? LINK_STATE_INITIALIZED : LINK_STATE_PENDING))
+        if (udev_available() && !link->dev)
                 return 0;
 
+        link->ethtool_driver_read = true;
+
         r = ethtool_get_driver(&link->manager->ethtool_fd, link->ifname, &link->driver);
         if (r < 0) {
                 log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
@@ -2064,20 +2066,46 @@ static int link_update_driver(Link *link, sd_netlink_message *message) {
         return 0;
 }
 
-static int link_update_permanent_hardware_address(Link *link, sd_netlink_message *message) {
+static int link_update_permanent_hardware_address_from_ethtool(Link *link, sd_netlink_message *message) {
         int r;
 
         assert(link);
         assert(link->manager);
         assert(message);
 
-        if (link->permanent_hw_addr.length > 0)
+        if (link->ethtool_permanent_hw_addr_read)
                 return 0;
 
         /* When udevd is running, read the permanent hardware address after the interface is
          * initialized by udevd. Otherwise, ethtool may not work correctly. See issue #22538.
          * When udevd is not running, read the value when the interface is detected. */
-        if (link->state != (udev_available() ? LINK_STATE_INITIALIZED : LINK_STATE_PENDING))
+        if (udev_available() && !link->dev)
+                return 0;
+
+        /* If the interface does not have a hardware address, then it will not have a permanent address either. */
+        r = netlink_message_read_hw_addr(message, IFLA_ADDRESS, NULL);
+        if (r == -ENODATA)
+                return 0;
+        if (r < 0)
+                return log_link_debug_errno(link, r, "Failed to read IFLA_ADDRESS attribute: %m");
+
+        link->ethtool_permanent_hw_addr_read = true;
+
+        r = ethtool_get_permanent_hw_addr(&link->manager->ethtool_fd, link->ifname, &link->permanent_hw_addr);
+        if (r < 0)
+                log_link_debug_errno(link, r, "Permanent hardware address not found, continuing without: %m");
+
+        return 0;
+}
+
+static int link_update_permanent_hardware_address(Link *link, sd_netlink_message *message) {
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(message);
+
+        if (link->permanent_hw_addr.length > 0)
                 return 0;
 
         r = netlink_message_read_hw_addr(message, IFLA_PERM_ADDRESS, &link->permanent_hw_addr);
@@ -2085,12 +2113,10 @@ static int link_update_permanent_hardware_address(Link *link, sd_netlink_message
                 if (r != -ENODATA)
                         return log_link_debug_errno(link, r, "Failed to read IFLA_PERM_ADDRESS attribute: %m");
 
-                if (netlink_message_read_hw_addr(message, IFLA_ADDRESS, NULL) >= 0) {
-                        /* Fallback to ethtool, if the link has a hardware address. */
-                        r = ethtool_get_permanent_hw_addr(&link->manager->ethtool_fd, link->ifname, &link->permanent_hw_addr);
-                        if (r < 0)
-                                log_link_debug_errno(link, r, "Permanent hardware address not found, continuing without: %m");
-                }
+                /* Fallback to ethtool for older kernels. */
+                r = link_update_permanent_hardware_address_from_ethtool(link, message);
+                if (r < 0)
+                        return r;
         }
 
         if (link->permanent_hw_addr.length > 0)
index 9f1cdca31272a2153b3132d8bd029d848edf0988..4d397da79a216cf925983b1d9c219c507c676ac6 100644 (file)
@@ -72,6 +72,10 @@ typedef struct Link {
         sd_device *dev;
         char *driver;
 
+        /* to prevent multiple ethtool calls */
+        bool ethtool_driver_read;
+        bool ethtool_permanent_hw_addr_read;
+
         /* link-local addressing */
         IPv6LinkLocalAddressGenMode ipv6ll_address_gen_mode;