From 807fe764111b5a74cc8618b8e4ec437a0dec91ff Mon Sep 17 00:00:00 2001
From: Lukas Nykryn <lnykryn@redhat.com>
Date: Thu, 19 Oct 2023 10:38:06 +0200
Subject: [PATCH 7018/7019] udev: add new builtin net_driver

Currently the ID_NET_DRIVER is set in net_setup_link builtin.
But this is called pretty late in the udev processing chain.

Right now in some custom rules it was workarounded by calling ethtool
binary directly, which is ugly.

So let's split this code to a separate builtin.

(cherry picked from commit 2b5b25f123ceb89b3ff45b2380db1c8a88b046d9)
---
 rules.d/50-udev-default.rules.in       |  2 ++
 src/udev/meson.build                   |  1 +
 src/udev/net/link-config.c             |  5 ++-
 src/udev/net/link-config.h             |  2 +-
 src/udev/udev-builtin-net_driver.c     | 43 ++++++++++++++++++++++++++
 src/udev/udev-builtin-net_setup_link.c |  3 --
 src/udev/udev-builtin.c                |  1 +
 src/udev/udev-builtin.h                |  2 ++
 8 files changed, 52 insertions(+), 7 deletions(-)
 create mode 100644 src/udev/udev-builtin-net_driver.c

diff --git a/rules.d/50-udev-default.rules.in b/rules.d/50-udev-default.rules.in
index 3722a927f5..9b00c7037e 100644
--- a/rules.d/50-udev-default.rules.in
+++ b/rules.d/50-udev-default.rules.in
@@ -28,6 +28,8 @@ ENV{MODALIAS}!="", IMPORT{builtin}="hwdb --subsystem=$env{SUBSYSTEM}"
 # To keep the backward compatibility, let's set ID_PATH for them.
 SUBSYSTEM=="pci|usb|platform", IMPORT{builtin}="path_id"
 
+SUBSYSTEM=="net", IMPORT{builtin}="net_driver"
+
 ACTION!="add", GOTO="default_end"
 
 SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666"
diff --git a/src/udev/meson.build b/src/udev/meson.build
index ac71e07900..3d6769e8e2 100644
--- a/src/udev/meson.build
+++ b/src/udev/meson.build
@@ -28,6 +28,7 @@ libudevd_core_sources = files(
         'udev-builtin-hwdb.c',
         'udev-builtin-input_id.c',
         'udev-builtin-keyboard.c',
+        'udev-builtin-net_driver.c',
         'udev-builtin-net_id.c',
         'udev-builtin-net_setup_link.c',
         'udev-builtin-path_id.c',
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
index b554a6827d..2a783bbf30 100644
--- a/src/udev/net/link-config.c
+++ b/src/udev/net/link-config.c
@@ -364,7 +364,6 @@ Link *link_free(Link *link) {
 
         sd_device_unref(link->device);
         free(link->kind);
-        free(link->driver);
         strv_free(link->altnames);
         return mfree(link);
 }
@@ -417,8 +416,8 @@ int link_new(LinkConfigContext *ctx, sd_netlink **rtnl, sd_device *device, Link
                         log_link_debug_errno(link, r, "Failed to get permanent hardware address, ignoring: %m");
         }
 
-        r = ethtool_get_driver(&ctx->ethtool_fd, link->ifname, &link->driver);
-        if (r < 0)
+        r = sd_device_get_property_value(link->device, "ID_NET_DRIVER", &link->driver);
+        if (r < 0 && r != -ENOENT)
                 log_link_debug_errno(link, r, "Failed to get driver, ignoring: %m");
 
         *ret = TAKE_PTR(link);
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
index 713d41040a..bab9d12970 100644
--- a/src/udev/net/link-config.h
+++ b/src/udev/net/link-config.h
@@ -34,7 +34,7 @@ typedef struct Link {
         sd_device_action_t action;
 
         char *kind;
-        char *driver;
+        const char *driver;
         uint16_t iftype;
         uint32_t flags;
         struct hw_addr_data hw_addr;
diff --git a/src/udev/udev-builtin-net_driver.c b/src/udev/udev-builtin-net_driver.c
new file mode 100644
index 0000000000..f1642a491d
--- /dev/null
+++ b/src/udev/udev-builtin-net_driver.c
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "alloc-util.h"
+#include "device-util.h"
+#include "errno-util.h"
+#include "ethtool-util.h"
+#include "fd-util.h"
+#include "log.h"
+#include "string-util.h"
+#include "udev-builtin.h"
+
+static int builtin_net_driver_set_driver(UdevEvent *event, int argc, char **argv, bool test) {
+        sd_device *dev = ASSERT_PTR(ASSERT_PTR(event)->dev);
+        _cleanup_close_ int ethtool_fd = -EBADF;
+        _cleanup_free_ char *driver = NULL;
+        const char *sysname;
+        int r;
+
+        r = sd_device_get_sysname(dev, &sysname);
+        if (r < 0)
+                return log_device_warning_errno(dev, r, "Failed to get sysname: %m");
+
+        r = ethtool_get_driver(&ethtool_fd, sysname, &driver);
+        if (ERRNO_IS_NEG_NOT_SUPPORTED(r)) {
+                log_device_debug_errno(dev, r, "Querying driver name via ethtool API is not supported by device '%s', ignoring: %m", sysname);
+                return 0;
+        }
+        if (r == -ENODEV) {
+                log_device_debug_errno(dev, r, "Device already vanished, ignoring.");
+                return 0;
+        }
+        if (r < 0)
+                return log_device_warning_errno(dev, r, "Failed to get driver for '%s': %m", sysname);
+
+        return udev_builtin_add_property(event->dev, test, "ID_NET_DRIVER", driver);
+}
+
+const UdevBuiltin udev_builtin_net_driver = {
+        .name = "net_driver",
+        .cmd = builtin_net_driver_set_driver,
+        .help = "Set driver for network device",
+        .run_once = true,
+};
diff --git a/src/udev/udev-builtin-net_setup_link.c b/src/udev/udev-builtin-net_setup_link.c
index 5bc965f6d8..a308a211fb 100644
--- a/src/udev/udev-builtin-net_setup_link.c
+++ b/src/udev/udev-builtin-net_setup_link.c
@@ -29,9 +29,6 @@ static int builtin_net_setup_link(UdevEvent *event, int argc, char **argv, bool
         if (r < 0)
                 return log_device_warning_errno(dev, r, "Failed to get link information: %m");
 
-        if (link->driver)
-                udev_builtin_add_property(dev, test, "ID_NET_DRIVER", link->driver);
-
         r = link_get_config(ctx, link);
         if (r < 0) {
                 if (r == -ENOENT) {
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index a8dd656b00..bcc2018c6f 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -22,6 +22,7 @@ static const UdevBuiltin *const builtins[_UDEV_BUILTIN_MAX] = {
 #if HAVE_KMOD
         [UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
 #endif
+        [UDEV_BUILTIN_NET_DRIVER] = &udev_builtin_net_driver,
         [UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
         [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_setup_link,
         [UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
diff --git a/src/udev/udev-builtin.h b/src/udev/udev-builtin.h
index b2cf81ad31..fcd41d615d 100644
--- a/src/udev/udev-builtin.h
+++ b/src/udev/udev-builtin.h
@@ -20,6 +20,7 @@ typedef enum UdevBuiltinCommand {
 #if HAVE_KMOD
         UDEV_BUILTIN_KMOD,
 #endif
+        UDEV_BUILTIN_NET_DRIVER,
         UDEV_BUILTIN_NET_ID,
         UDEV_BUILTIN_NET_LINK,
         UDEV_BUILTIN_PATH_ID,
@@ -64,6 +65,7 @@ extern const UdevBuiltin udev_builtin_keyboard;
 #if HAVE_KMOD
 extern const UdevBuiltin udev_builtin_kmod;
 #endif
+extern const UdevBuiltin udev_builtin_net_driver;
 extern const UdevBuiltin udev_builtin_net_id;
 extern const UdevBuiltin udev_builtin_net_setup_link;
 extern const UdevBuiltin udev_builtin_path_id;
-- 
2.43.0

