]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: do not regenerate MAC address if already set by userspace
authorShihao Ren <renshihao.rsh@bytedance.com>
Fri, 10 Jul 2026 07:26:27 +0000 (15:26 +0800)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 11 Jul 2026 15:00:01 +0000 (00:00 +0900)
When MACAddress= is unspecified, a stable MAC is generated to seed a newly
created netdev. Since existing netdevs are reconfigured on reload/restart,
this seed got re-applied to an already existing interface, conflicting with
an explicit MACAddress= from the matching .network file and flipping MAC.

Now, when MACAddress= is unspecified, only generate a new address if
addr_assign_type is not NET_ADDR_SET (i.e. not already set by userspace). On
first creation the interface does not exist yet, so this is a no-op and the
address is generated as before. Mirrors src/udev/net/link-config.c.

Fixes: #42457
src/network/netdev/netdev.c

index 658eb1808f1da0ab2ea8872f329f8ef859cd4a20..74b036a7ad5ed5f7db038b5f85ba2e4f331c91f3 100644 (file)
@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
 #include <linux/if_arp.h>
+#include <linux/netdevice.h>
 #include <unistd.h>
 
 #include "sd-netlink.h"
@@ -14,6 +15,7 @@
 #include "condition.h"
 #include "conf-files.h"
 #include "conf-parser.h"
+#include "device-private.h"
 #include "dummy.h"
 #include "fou-tunnel.h"
 #include "geneve.h"
@@ -575,6 +577,21 @@ int netdev_generate_hw_addr(
                 if (!IN_SET(NETDEV_VTABLE(netdev)->iftype, ARPHRD_ETHER, ARPHRD_INFINIBAND))
                         goto finalize;
 
+                /* If the interface already exists and its MAC address has been set by userspace
+                 * (e.g. through MACAddress= in the matching .network file, or manually), do not
+                 * generate a new address. Otherwise, on reconfiguration the generated address would
+                 * override the one set by userspace and, as they differ, both would be re-applied on
+                 * every reload/restart. See issue #42457. */
+                Link *link;
+                unsigned addr_assign_type;
+                if (link_get_by_index(netdev->manager, netdev->ifindex, &link) >= 0 &&
+                    link->dev &&
+                    device_get_sysattr_unsigned(link->dev, "addr_assign_type", &addr_assign_type) >= 0 &&
+                    addr_assign_type == NET_ADDR_SET) {
+                        log_netdev_debug(netdev, "MAC address is already set by userspace, not generating a new one.");
+                        goto finalize;
+                }
+
                 r = net_get_unique_predictable_data_from_name(name, &HASH_KEY, &result);
                 if (r < 0) {
                         log_netdev_warning_errno(netdev, r,
@@ -964,6 +981,13 @@ static int independent_netdev_process_request(Request *req, Link *link, void *us
                 return 1; /* Skip this request. */
         }
 
+        Link *existing;
+        if (link_get_by_index(netdev->manager, netdev->ifindex, &existing) >= 0 &&
+            IN_SET(existing->state,
+                   LINK_STATE_PENDING, /* Already exists and is being processed by udevd. Postpone the request. */
+                   LINK_STATE_LINGER)) /* Already removed; wait for the stale information to be cleared. */
+                return 0;
+
         r = netdev_is_ready_to_create(netdev, NULL);
         if (r <= 0)
                 return r;