[PATCH 3/3] net: add generic MAC address derivation from machine ID
Sascha Hauer
sha at pengutronix.de
Tue Sep 12 03:49:03 PDT 2023
On Mon, Sep 11, 2023 at 05:59:27PM +0200, Ahmad Fatoum wrote:
> From: Ahmad Fatoum <ahmad at a3f.at>
>
> 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 |
More information about the barebox
mailing list