MichaIng / DietPi

Lightweight justice for your single-board computer!
https://dietpi.com/
GNU General Public License v2.0
4.88k stars 497 forks source link

NanoPi 5/6 | Set/change MAC address persistently #6565

Open owendelong opened 1 year ago

owendelong commented 1 year ago

Creating a feature request

Is your feature request related to a problem? Please describe:

I often find it useful to get a system very close to what I want on multiple systems and then use dd to clone the entire drive, then change a few settings like IP Addresses, Hostname, etc. (personality files as it were) to make a new system with similar functionality.

On DietPI (at least on NanoPi R6S and I admit it's hard for me to know whether this is hardware or software-related), this results in the MAC address(es) coming along for the ride (which is not desired). Booting a clean NanoPI installer allows me to see the original MAC address, but there's no documented way to stop the device from booting with the cloned address(es) (which is problematic in a number of ways).

Describe the solution you'd like:

Clear documentation of where and how the persistent MAC addresses for the interfaces are stored. A utility for restoring them to the hardware original addresses would be a bonus (for systems that have burned in addresses).

Describe alternatives you've considered:

I've tried multiple techniques to search the filesystem for the address without any luck.

Additional context

This particular set of NanoPI R6S units are being used as routers with two tagged (multiple VLAN) interfaces (internal LANs, Guest/DMZ LANs) and one external interface. Having duplicate MAC addresses hitting the ISP's upstream router for DHCP creates all kinds of (not) fun.

Joulinar commented 1 year ago

Does this fir your request? https://github.com/MichaIng/DietPi/issues/3618

owendelong commented 1 year ago

Not really... /etc/network/interfaces only updates the MAC address on interfaces with an IP configuration. Problem is I'm running tagged interfaces, so for example, eth1 has no IP configuration, but needs a MAC address (non-conflicting) for eth1.1, eth1.10, eth1.19, eth1.20, eth1.90, eth1,91, and eth1.100.

The MAC addresses on the sub interfaces are copied from the main interface, but overriding them in interfaces leads to "interesting" results on the wire which are not the needed result.

MichaIng commented 1 year ago

I guess the MAC address is set via bootloader config (or kernel commend-line?), and that one is hidden on one of the partitions 1-7 🤔.

Isn't it possible to set the MAC address via /etc/network/interfaces(.d/some.conf) for eth1 without setting any IP address or other value? The interfaces are brought up in the order they appear in the configs, so it should be possible to first only chance the MAC of eth1 and then bring up the VLANs. If really not possible via interface config, then:

ip l set dev eth1 address XX:XX:XX:XX:XX:XX

This can be also done in the interface config via pre-up config key.

owendelong commented 1 year ago

I suppose that technique might work. What I had been trying was: `allow-hot plug eth1 auto eth1 iface eth1 enet static hwaddress xx:xx:xx:yy:yy:yy

iface eth1.1 enet static ... `

Putting the straight command in interfaces.d does, indeed, work, but it would still be nice to know what it takes to reset the BIA in the earlier partitions.

owendelong commented 1 year ago

If you configure an hw-address on an interface without setting an IP address on that interface, it reports a “required parameter missing” error and skips the interface. OwenOn Aug 22, 2023, at 14:21, MichaIng @.***> wrote: I guess the MAC address is set via bootloader config (or kernel commend-line?), and that one is hidden on one of the partitions 1-7 🤔. Isn't it possible to set the MAC address via /etc/network/interfaces(.d/some.conf) for eth1 without setting any IP address or other value? The interfaces are brought up in the order they appear in the configs, so it should be possible to first only chance the MAC of eth1 and then bring up the VLANs. If really not possible via interface config, then: ip l set dev eth1 address XX:XX:XX:XX:XX:XX This can be also done in the interface config via pre-up config key.

—Reply to this email directly, view it on GitHub, or unsubscribe.You are receiving this because you authored the thread.Message ID: @.***>

MichaIng commented 1 year ago

Okay, that is nasty. But the ip l set ... command works, right? If not possible via interfaces config, then drop-in config for the networking.service should do:

mkdir -p /etc/systemd/system/networking.service.d
echo -e '[Service]\nExecStartPre=/sbin/ip l set dev eth1 address XX:XX:XX:XX:XX:XX' > /etc/systemd/system/networking.service.d/set_mac.conf

About the boot environment, the fw_printenv command of the libubootenv-tool package might help to find the partition and check the content/environment, and fw_setenv can be used to alter it. But it requires a configuration file /etc/fw_env.config to point to the correct partition. I'll have a look into this tomorrow.

owendelong commented 1 year ago

The suggestion in interfaces using the directory entry and ip link set full command line syntax (vs. the intended hw-address syntax documented in the interfaces(5) manage) does work.

All of these are ugly and it would be useful to have a tool or documentation of how to tweak the boot environment.

FWIW, I have not (as yet) been able to figure out the right incantation to put into the fw_env.config file, so if someone better versed in this stuff than me finds that, documenting it would be VERY useful.

MichaIng commented 1 year ago

Sorry for the delay. I'm on a trip currently but will be back on Sunday to investigate this on my R5S.

MichaIng commented 8 months ago

The problem is likely fixed with our new images, based on kernel and bootloader generated with Armbian build system. I'll update our download page tomorrow, until then they can be found here: https://dietpi.com/downloads/images/testing/

Bucking-Horn commented 8 months ago

Just curious: Does that fix make use of custom device tree overlays?

I've found that to be the most 'complete' / earliest approach on a NanoPi Neo, see https://forum.armbian.com/topic/14525-mac-address-of-eth0-changes-on-every-boot/?do=findComment&comment=121525

MichaIng commented 8 months ago

No, just using a different kernel: We used the one from FriendlyELEC previously, now Armbian. But at least the two LAN ports on NanoPi R5S still have a random MAC, just the WAN port has a permanent one: #6951

I'll check the other SBCs when I find time. The fix with the device tree looks interesting. If it is really just a missing ethernetN alias (or several), then this would be easy to fix, although better at Armbian directly as device tree patch, and/or even upstream Linux, instead of applying an overlay.

owendelong commented 7 months ago

For R6S might I humbly suggest taking the WAN port MAC or(boolean) 0x02:00:00:00:00:00 +1 and +2 respectively for the other ports so that you have a reasonably predictable number that is still valid.

MichaIng commented 7 months ago

The MAC addesses should be at best set with whichever common logic the kernel uses, based on individual adapter, not set/overwritten by us, and definitely not hardcoded (which would break running multiple NanoPi's on the same subnet.

owendelong commented 7 months ago

Your last comment was not incompatible with my suggestion. You mentioned that only the WAN port has a MAC address on the R6S... Currently, I believe we (or something) is generating randomized MAC addresses for the other ports. If we are generating the randomized address, I'm suggesting that instead of Random, we create one that is predictably related to the WAN port address, yet still technically correct.

Doing the |0x02 to the first octet will change the address from globally managed to locally assigned. Incrementing the last octet per port will make it clear that the address is a different interface.

(I think this is better than what Sun used to do which was code the MAC address for the system into the hostid chip and then use the same EUI-48 on every interface).

Example, let's say I have an R6S with MAC c0:e8:dc:e9:f8:e1 on the WAN (eth2). I'm proposing that the result would become: eth0: c2:e8:dc:e9:f8:e2 eth1: c2:e8:dc:e9:f8:e3 eth2: c0:e8:dc:e9:f8:e1

Hope that is more clear.

MichaIng commented 7 months ago

What I meant is that usually the MAC address is based on the individual adapters hardware attributes, not random and not based on another adapters attributes. It should be the same, no matter which system the adapter is attached to. This is what we should try to restore.

owendelong commented 7 months ago

Ideally yes. I don't think that the NanoPi hardware has burned in addresses. This is actually not unusual on SoC and SBC systems.

owendelong commented 7 months ago

OTOH, on systems that do have multiple interfaces, it is not at all unusual for the manufacturer to supply consecutive MACs for the interfaces.

MichaIng commented 2 months ago

The WAN port of the R5S has a static mac address, I guess because this attribute is defined:

/proc/device-tree/ethernet@fe2a0000/local-mac-address

But I do not see where it is defined, neither in Armbian patches, nor in Linux sources:

The second adapter is defined here: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/arm64/boot/dts/rockchip/rk356x.dtsi?h=linux-6.6.y#n662 I see it on the device below /proc/device-tree, so for that one, we could add/set local-mac-address = [00 00 00 00 00 00]; as well. But I do not see the 3rd adapter defined anywhere on my R5S. Hence I don't know its name/address or alias and hence cannot add local-mac-address = [00 00 00 00 00 00]; there. But step by step. First of all we can try to add it to the visible node and see whether one of the LAN1/LAN2 ports has a static MAC address afterwards.

MichaIng commented 1 month ago

Sadly it does not work, tried like this:

/dts-v1/;
/plugin/;
/ {
        fragment@0 {
                target-path = "/ethernet@fe010000";
                __overlay__ {
                        local-mac-address = [00 00 00 00 00 00];
                };
        };
};

As well as other syntax

/dts-v1/;
/plugin/;
&{/ethernet@fe010000} {
        local-mac-address = [00 00 00 00 00 00];
};

But while /proc/device-tree/ethernet@fe010000/local-mac-address exists in both cases, hence the overlay has been applied, the MAC address of the two LAN1/LAN2 ports keep changing. I am still wondering why there are 2 Ethernet nodes only, while it has 3 ports. 2 of them likely share the same controller? But how to apply the local-mac-address correctly in this case, to be effective for both ports?

IdunW commented 1 month ago

I'm having the same issue with the MAC adresses changing on NanoPC T6 and thus disabling some very important licenses i need. Looking for a permanent fix to this. I found this article, quite new at this myself but maybe someone with a bit more experience could tell me if it could work or not?

https://en.wikibooks.org/wiki/Hacking/Tools/Network/Changing_Your_MAC_Address/Linux

MichaIng commented 1 month ago

@IdunW Jep, this is basically the workaround we suggested above: https://github.com/MichaIng/DietPi/issues/6565#issuecomment-1694492893 While it works, best would be to have the "original" MAC address of the adapter applied right at early boot/kernel-wise, instead of doing it later in userland. But sadly, the simply approach which worked for the NanoPi NEO and some M.2 WiFi modules does not work here.

But I actually want to test it on the NanoPi R6C, with only 2 Ethernet ports. I guess it has to do something with the fact that one controller is responsible for 2 ports, if I am not all wrong, hence that /ethernet@fe010000 is the node for both LAN1 and LAN2, and local-mac-address would need to be applied differently for each particular port.

MichaIng commented 1 month ago

Ah, now actually I missed the part from the Armbian forum, that not only the local-mac-address is essential, but also the ethernet0 alias. While that one exists IIRC, for the WAN port (which would explain why that one has a static MAC), maybe ethernet1 at least needs to exist as well. Still unsure about ethernet2, respectively how to address LAB2 or differentiate between LAN1 and LAN2 at this point.

IdunW commented 1 month ago

@MichaIng Alright, i understand. i'm considering testing out a NanoPI M6 with only one ethernet port, if it can run what i need almost as well as the T6. I would greatly appreciate updates if you get this to work with the RC6, and i will post here if i somehow get this to work on the T6.

What i need is a fix that can be included in an image, that can be cloned to several new machines, the MAC addresses need to be unique per machine and have no way of randomly changing later on.

I have contacted FriendlyELEC about this aswell, with the reply being very vague and non-informative so i guess there's no help there. FriendlyELEC answer

MichaIng commented 1 month ago

Hehe, yeah with userland tools of course one can assign MAC addresses manually. What I am looking for is having the bootloader doing it automatically, and the one which every other OS would assign as well, based on hardware details. At least I think such native MAC exists for every network adapter?

Here is the U-Boot docs I will have a loot into tonight, and test above mentioned device tree changes: https://github.com/u-boot/u-boot/blob/master/doc/README.enetaddr

MichaIng commented 1 month ago

Tried this now

/dts-v1/;
/plugin/;
/ {
        fragment@0 {
                target-path = "/aliases";
                __overlay__ {
                        ethernet1 = "/ethernet@fe010000";
                };
        };
        fragment@1 {
                target-path = "/ethernet@fe010000";
                __overlay__ {
                        local-mac-address = [00 00 00 00 00 00];
                };
        };
};

And afterwards, I recognised that /ethernet@fe010000 is actually disabled, hence definitely not the eth1 adapter. It also does not work. So the issue remains that we have the ethernet0 alias only, where all above things are set and hence the WAN MAC address is static, but I have no idea how to know/define/alter the nodes for the LAN1 and LAN2 adapters.

Defining ethaddr/eth1addr/eth2addr does not work either. So I am at the end with my knowledge here. Looks like there is a reason why also OpenWRT generates and assigns a MAC address in userland, interestingly based on SD card/MMC hardware identifiers, to have an individual default per system.

For us, IMO it is best to have a GUI to apply a static IP similar to this: https://github.com/MichaIng/DietPi/issues/6565#issuecomment-1694492893 Best probably is using udev rules, or /etc/network/if-pre-up.d/.

IdunW commented 1 month ago

I seem to have gotten it to work with 2 Ethernet adapters on the NanoPC T6 now. Done 10 reboots with updates and it stays on the same MAC and HWID.

First i had to install NetworkManager. Then in the config file below: sudo nano /etc/NetworkManager/NetworkManager.conf


I added this after everything else:

[device]
wifi.scan-rand-mac-address=no
ethernet.cloned-mac-address=preserve

Then restarted NetworkManager; sudo systemctl restart NetworkManager

and rebooted the NanoPC

This fixed the MAC adresses to be permanent on both ports, but it seems it changes which port is the main one so it was switching between the two on every boot.

Then i used cockpit, they have a built in way to put the MAC Adresses as ''permanent'' for each port in the Network tab. After doing this the PC stopped swapping between the two and has been stable so far.

Hope this helps, and that it stays permanent. Only been a week or so now and i need to foolproof this fix so i will update if i run into any problems along the way.

IdunW commented 1 month ago

Also worth mentioning that i found out that the ports were called end0 and end1 instead of the usual eth0/eth1 so maybe that could be a reason why its difficult to define them?

MichaIng commented 4 weeks ago

@IdunW then you do not seem to use an original DietPi image? These "predictable" network interface names are disabled by default on DietPi.

Good to know that NetMan has an internal option to store and recover MAC addresses. ifupdown also has the hwaddress option. As said, there are various methods to achieve this in userland. What I was aiming for is making it static via bootloader/kernel, but that seems to be impossible, or at least not trivial with this hardware.