On Mon, Sep 11, 2023 at 05:59:27PM +0200, Ahmad Fatoum wrote: > From: Ahmad Fatoum <ahmad@xxxxxx> > > Especially during development, devices often lack a MAC address. While a > MAC address can be easily added to the environment: > > nv dev.eth0.ethaddr="aa:bb:cc:dd:ee:ff" > > It's easily lost when flashing complete new images, e.g. from CI. > Make the development experience neater by deriving a stable MAC address > if possible. I like this, because my Fritzbox network overview is full of duplicate entries coming from boards with random MAC addresses. > @@ -558,6 +559,7 @@ static int of_populate_ethaddr(void) This function should be renamed. When reviewing this patch I asked myself why you limit generating a fixed MAC address to the DT case until I realized that you actually don't. I was just confused by the function name. > { > char str[sizeof("xx:xx:xx:xx:xx:xx")]; > struct eth_device *edev; > + bool generated = false; > int ret; > > list_for_each_entry(edev, &netdev_list, list) { > @@ -566,11 +568,18 @@ static int of_populate_ethaddr(void) > > ret = of_get_mac_addr_nvmem(edev->parent->of_node, > edev->ethaddr); > + if (ret && IS_ENABLED(CONFIG_NET_ETHADDR_FROM_MACHINE_ID)) { This check doesn't seem to be needed, generate_ether_addr() already returns -ENOSYS when this option is not enabled. > + ret = generate_ether_addr(edev->ethaddr, edev->dev.id); > + generated = true; > + } > if (ret) > continue; > > ethaddr_to_string(edev->ethaddr, str); > - dev_info(&edev->dev, "Got preset MAC address from device tree: %s\n", str); > + if (generated) > + dev_notice(&edev->dev, "Generated MAC address from unique id: %s\n", str); > + else > + dev_info(&edev->dev, "Got preset MAC address from NVMEM: %s\n", str); > eth_set_ethaddr(edev, edev->ethaddr); > } > > diff --git a/net/net.c b/net/net.c > index bf2117ff7ec2..e38179491d7a 100644 > --- a/net/net.c > +++ b/net/net.c > @@ -25,6 +25,7 @@ > #include <init.h> > #include <globalvar.h> > #include <magicvar.h> > +#include <machine_id.h> > #include <linux/ctype.h> > #include <linux/err.h> > > @@ -365,6 +366,43 @@ IPaddr_t net_get_gateway(void) > > static LIST_HEAD(connection_list); > > +/** > + * generate_ether_addr - Generates stable software assigned Ethernet address > + * @addr: Pointer to a six-byte array to contain the Ethernet address > + * @ethid: index of the Ethernet interface > + * > + * Derives an Ethernet address (MAC) from the machine ID, that's stable > + * per board that is not multicast and has the local assigned bit set. > + * > + * Return 0 if an address could be generated or a negative error code otherwise. > + */ > +int generate_ether_addr(u8 *ethaddr, int ethid) > +{ > + const char *hostname; > + uuid_t id; > + int ret; > + > + if (!IS_ENABLED(CONFIG_NET_ETHADDR_FROM_MACHINE_ID)) > + return -ENOSYS; > + > + hostname = barebox_get_hostname(); > + if (!hostname) > + return -EINVAL; > + > + ret = machine_id_get_app_specific(&id, ARRAY_AND_SIZE("barebox-macaddr:"), > + hostname, strlen(hostname), NULL); > + if (ret) > + return ret; > + > + memcpy(ethaddr, &id.b, ETH_ALEN); > + eth_addr_add(ethaddr, ethid); > + > + ethaddr[0] &= 0xfe; /* clear multicast bit */ > + ethaddr[0] |= 0x02; /* set local assignment bit (IEEE802) */ > + > + return 0; > +} > + > static struct net_connection *net_new(struct eth_device *edev, IPaddr_t dest, > rx_handler_f *handler, void *ctx) > { > @@ -381,9 +419,16 @@ static struct net_connection *net_new(struct eth_device *edev, IPaddr_t dest, > > if (!is_valid_ether_addr(edev->ethaddr)) { > char str[sizeof("xx:xx:xx:xx:xx:xx")]; > - random_ether_addr(edev->ethaddr); > + > + ret = generate_ether_addr(edev->ethaddr, edev->dev.id); For most network devices we won't get here because of_populate_ethaddr() will already have done it for us. It's only used for devices that are probed after postenvironment_initcall(), namely USB devices. I think this deserves a cleanup before we merge this. The original reason to introduce a postenvironment_initcall() for getting the MAC address from nvmem was: > We do this in a very late initcall, because we don't want to enforce a > probe a probe order between nvmem providers and network devices. We > can't do it at randomization time, because we need to fixup Ethernet mac > addresses, even when barebox itself doesn't ifup the netdev. I think we should have one centralized function that retrieves the MAC address for an ethernet device. That should be called when we actually need that MAC address, so once in net_new() and once at of_fixup time. Right now the behaviour is inconsistent with regard to random MAC addresses. Currently we propagate the random MAC address to the Linux device tree when we use ethernet in barebox, but we don't propagate it when we do not use ethernet in barebox. We should decide what the desired behaviour is and do it consistently regardless if we use ethernet in barebox or not. This could be cleaned up along the way. Sascha -- Pengutronix e.K. | | Steuerwalder Str. 21 | http://www.pengutronix.de/ | 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 |