udevd: `Could not generate persistent MAC address for $name: No such file or directory` #3374

Open
tomty89 opened this Issue May 28, 2016 · 23 comments

Comments

Projects
None yet
Contributor

tomty89 commented May 28, 2016

Submission type

  • Bug report
  • Request for enhancement (RFE)

systemd version the issue has been seen with

230

Used distribution

Arch Linux

In case of bug report: Expected behaviour you didn't see

no message is logged when I add an interface with ip link

In case of bug report: Unexpected behaviour you saw

Could not generate persistent MAC address for $name: No such file or directory logged when I add an interface (e.g. bridge, bond) with ip link. If I create them with networkd/.netdev, no such message is logged.

In case of bug report: Steps to reproduce the problem

[tom@localhost ~]$ sudo ip l add name br0 type bridge
[tom@localhost ~]$ sudo ip l add name bond1 type bond
[tom@localhost ~]$ journalctl -b -u systemd-udevd
-- Logs begin at Wed 2016-05-04 14:49:19 HKT, end at Sat 2016-05-28 15:39:18 HKT. --
May 28 15:39:13 localhost systemd-udevd[351]: Could not generate persistent MAC address for br0: No such file or directory
May 28 15:39:18 localhost systemd-udevd[358]: Could not generate persistent MAC address for bond0: No such file or directory
May 28 15:39:18 localhost systemd-udevd[357]: Could not generate persistent MAC address for bond1: No such file or directory

Contributor

tomty89 commented Jun 4, 2016

So this is the cause of the issue:

systemd.link(5), for MACAddressPolicy=persistent:

This feature depends on ID_NET_NAME_* properties to exist for the link. On hardware where these properties are not set, the generation of a persistent MAC address will fail.

which does not really make sense for "virtual devices" (i.e. bridge, bond...), but they are "affected" since we generally defaults to MACAddressPolicy=persistent.

What do you think, @teg? Do you think this makes sense?

diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 046b0f9..863ce26 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -44,6 +44,12 @@ const char *net_get_name(struct udev_device *device) {

         assert(device);

+        if (!udev_device_get_property_value(device, "ID_BUS")) {
+                name = udev_device_get_property_value(device, "INTERFACE");
+                if (name)
+                        return name;
+        }
+
         /* fetch some persistent data unique (on this machine) to this device */
         FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
                 name = udev_device_get_property_value(device, field);

@poettering poettering added this to the v231 milestone Jun 7, 2016

Contributor

teg commented Jun 8, 2016

Hm... I see the problem. But not sure I follow the patch. I guess what we want is in case the name of a device is set explicitly (i.e., one created from userspace), we can just use that as a seed for the MAC, that's what you are doing here, right?

Contributor

teg commented Jun 8, 2016

If I got that right, I think a better way is, in case the current logic fails, to look at name_assign_type (see should_rename()) and use the current ifname as seed if we know the name to be stable. Something like if (should_rename(device, true)). Does that make sense?

Owner

poettering commented Jul 22, 2016

@teg? @tomty89 any progress on this one?

@poettering poettering removed this from the v231 milestone Jul 22, 2016

Contributor

tomty89 commented Jul 22, 2016

Well I guess it's alright to use should_rename(). So when it returns false, we assume that the name can be used to seed the persistent MAC.

However, be noted that it will not cover virtual device that does not have the name_assign_type attribute. For example, bond0 that is created by default when the bonding module is loaded. I assume that's what we want though?

Shall we replace the following:

        /* fetch some persistent data unique (on this machine) to this device */
        FOREACH_STRING(field, "ID_NET_NAME_ONBOARD", "ID_NET_NAME_SLOT", "ID_NET_NAME_PATH", "ID_NET_NAME_MAC") {
                name = udev_device_get_property_value(device, field);
                if (name)
                        return name;
        }

with:

        if (!should_rename(device, true))
                return udev_device_get_sysname(device)

nezero commented Dec 22, 2016

Is there a reason the proposed fix hasn't been applied? This is blocking OpenVPN being able to bridge in some configurations.

Ping

@tomty89 @teg @poettering
If I understand correctly, changing the default behavior of the function net_get_name would cause unexpected changes of persistent MAC addresses, so the current logic should be kept.
And we can't call should_rename directly, as it is static.

I made the patch, and confirmed it is working for a bridge device.
Is there any problem on this solution?

diff --git a/src/libsystemd-network/network-internal.c b/src/libsystemd-network/network-internal.c
index 092a1eabb..d8fae2235 100644
--- a/src/libsystemd-network/network-internal.c
+++ b/src/libsystemd-network/network-internal.c
@@ -40,7 +40,8 @@
 #include "util.h"
 
 const char *net_get_name(struct udev_device *device) {
-        const char *name, *field;
+        const char *name, *field, *s;
+        unsigned type;
 
         assert(device);
 
@@ -51,6 +52,12 @@ const char *net_get_name(struct udev_device *device) {
                         return name;
         }
 
+        /* if the machine doesn't provide data about the device, use the ifname specified by userspace
+        * (this is the case when the device is virtual, e.g., bridge or bond) */
+        s = udev_device_get_sysattr_value(device, "name_assign_type");
+        if (s && safe_atou(s, &type) >= 0 && type == NET_NAME_USER)
+                return udev_device_get_sysname(device);
+
         return NULL;
 }
 

I noticed that the above patch didn't fixed the issue for tun/tap devices.
Apparently the ioctl interface to create tun/tap devices does not set name_assign_type properly.
I locally patched drivers/net/tun.c on the kernel to pass NET_NAME_USER, then the problem is gone away.

Please @grafi-tt , can you share your patch? Thanks

djvdorp commented Mar 2, 2017

Any update on this matter? This also seems to cause issues for me in systemd v232 when using LXC:

/var/log/syslog:

Mar  2 16:00:59 localhost systemd-udevd[690]: Could not generate persistent MAC address for veth9A4JCF: No such file or directory

lxc-start output (as root) that triggers the above syslog entry:

lxc-start: conf.c: instantiate_veth: 2669 failed to attach 'veth9A4JCF' to the bridge 'lxcbr0': Operation not permitted
lxc-start: conf.c: lxc_create_network: 2962 failed to create netdev
lxc-start: start.c: lxc_spawn: 1088 Failed to create the network.
lxc-start: start.c: __lxc_start: 1346 Failed to spawn container "REDACTED"
lxc-start: tools/lxc_start.c: main: 366 The container failed to start.
lxc-start: tools/lxc_start.c: main: 370 Additional information can be obtained by setting the --logfile and --logpriority options.

A patch or workaround, maybe from @grafi-tt, would be greatly appreciated as I am stuck right now.

pawiecki commented Mar 8, 2017

As @nezero mentioned earlier, it affects OpenVPN on Fedora.

Fedora 25
Linux 4.9.13-200.fc25.x86_64
systemd 231
OpenVPN 2.3.14

mar 08 20:27:25 e320pw NetworkManager[1244]: <info>  [1489001245.0672] manager: (tap0): new Tun device (/org/freedesktop/NetworkManager/Devices/10)
mar 08 20:27:25 e320pw systemd-udevd[4164]: Could not generate persistent MAC address for tap0: No such file or directory
mar 08 20:27:28 e320pw gnome-shell[1675]: JS LOG: Removing a network device that was not added
Contributor

tomty89 commented Mar 8, 2017

@grafi-tt I'm not sure what ioctl interface you were referring to but make you are aware the names of the virtual devices are not always "set from userspace", like the case of bond0 that is created upon the loading of the bonding modules (with default parameters, that said).

Also NET_NAME_USER may not be the only type that you want to "skip" (if we consider should_rename to be the reference, so you may want a clone of it here instead, or something like that that is sane in terms of programming)

I am not really sure it is the right way to address the issue though. As I said, virtual device that is not exactly created by user will still make udev error out. I wonder if we need to by some means make udev actually ignore them when it applies the MACAddressPolicy in any case, so that this issue is fully addressed.

any update on this one? it's still breaking openvpn

djvdorp commented Mar 21, 2017

Another bump from me as this is rather annoying to work with, because you can't.

Contributor

tomty89 commented Mar 23, 2017

For those who are having problem with this, you should be able work around it by copying /usr/lib/systemd/network/99-default.link to /etc/systemd/network/99-default.link and replace MACAddressPolicy=persistent with MACAddressPolicy=none in the latter, which should prevent udev from doing anything relevant.

Now it makes me wonder what's the point of MACAddressPolicy=. I mean, what's the sense of having systemd-wide (i.e. including devices that are not managed by networkd) general (i.e. physical and virtual devices that are either created by user explicitly or in some enumerated way) MAC Address Policy?

Physical devices mostly have "real" MAC Address which are inheritly persistent. Virtual devices created by users can be assigned with one explicitly if a random one is not acceptable. "Enumerated" device in special cases (e.g. bond0 created by the bonding module with its default parameter) probably wont have acceptable seed for persistent MAC Address generation anyway. So how come there should be a MAC policy applied by default "generally"? Let's say in some of the cases we do not want typical behavior, shouldn't that be switched per device or at most per type though?

@teg @poettering What do you think? Do you think we should/can at least change the default policy from persistent to none, until anyone is willing to spend time on making the option sensible?

@alfonsovng Sorry for the late response.
The patch is:

diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index cc88cd7856f5..6ddda452884d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -1777,6 +1777,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 	}
 	else {
 		char *name;
+		unsigned char name_assign_type = NET_NAME_ENUM;
 		unsigned long flags = 0;
 		int queues = ifr->ifr_flags & IFF_MULTI_QUEUE ?
 			     MAX_TAP_QUEUES : 1;
@@ -1799,11 +1800,13 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
 		} else
 			return -EINVAL;
 
-		if (*ifr->ifr_name)
+		if (*ifr->ifr_name) {
 			name = ifr->ifr_name;
+			name_assign_type = NET_NAME_USER;
+		}
 
 		dev = alloc_netdev_mqs(sizeof(struct tun_struct), name,
-				       NET_NAME_UNKNOWN, tun_setup, queues,
+				       name_assign_type, tun_setup, queues,
 				       queues);
 
 		if (!dev)

@tomty89 Thank you for pointing out the bond0 example. I don't have specific opinion, but maybe it is acceptable to just put warning when the name bond0 is matched. (If I understand correctly, there is another unsolved problem associated with bond0. https://bugs.freedesktop.org/show_bug.cgi?id=82956)

wow, over 12 months since initial report, still breaking openvpn and still no fix. why?

@mbiebl mbiebl deleted a comment from jmiahman Jul 5, 2017

Owner

poettering commented Jul 10, 2017

Bugs don't fix themselves. Generally, the best way to ensure a bug is fixed is becoming active yourself. We rely on contributions, like any Open Source project does.

We have a lot of work to do, and may priorize things differently from you, I hope that's understandable. that's why we can't work on all issues that arise with the same pressure. We are happy however for any contributions from outside

@poettering poettering deleted a comment from jmiahman Jul 11, 2017

@poettering poettering deleted a comment from unitylinux Jul 12, 2017

@poettering @grafi-tt
hi - we have encountered this problem, too. If I step in and try things out would you help with some guidance?

To start with,

  • So, the patch posted above by @grafi-tt is not yet part of v234?
  • If so, what can I do to test that patch?
  • I have found the HACKING file but I cannot find the file tun.c after cloning the repo?.. neither in master nor tag 234

GamerSource commented Sep 5, 2017

@1605200517

I have found the HACKING file but I cannot find the file tun.c after cloning the repo?.. neither in master nor tag 234

The last patch regarding TUN device from @grafi-tt is a Linux Kernel patch, not a systemd one.
You need to clone the kernel repo (either upstream or you distribution one) and add it there as a patch and compile the kernel yourself.
Together with the former patch from @grafi-tt (which is in fact a systemd) one you should be able to resolve this for all network device types, as far as I understand.

@GamerSource thank you; currently we no more get this

sathieu commented Oct 25, 2017

I've added (systemd 232, Debian 9 stretch):

# /etc/systemd/network/99-default.link
[Link]
NamePolicy=kernel database onboard slot path
MACAddressPolicy=none
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment