diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml index 9cbd99a0efc..bd493a8c53f 100644 --- a/man/systemd.netdev.xml +++ b/man/systemd.netdev.xml @@ -254,16 +254,22 @@ MACAddress= - The MAC address to use for the device. For tun or tap - devices, setting MACAddress= in the [NetDev] section is not - supported. Please specify it in the [Link] section of the corresponding + Specifies the MAC address to use for the device, or takes the special value + none. When none, systemd-networkd + does not request the MAC address for the device, and the kernel will assign a random MAC + address. For tun, tap, or l2tp + devices, the MACAddress= setting in the [NetDev] section is not + supported and will be ignored. Please specify it in the [Link] section of the corresponding systemd.network5 - file. If this option is not set, bridge and vlan devices - inherit the MAC address of the first slave device or the physical interface, respectively. For other - kind of netdevs, if this option is not set, then the MAC address is generated based on the interface - name and the + file. If this option is not set, vlan device inherits the MAC address of + the master interface. For other kind of netdevs, if this option is not set, then the MAC + address is generated based on the interface name and the machine-id5. + Note, even if none is specified, systemd-udevd + will assign the persistent MAC address for the device, as 99-default.link + has MACAddressPolicy=persistent. So, it is also necessary to create a + custom .link file for the device, if the MAC address assignment is not desired. diff --git a/src/network/netdev/batadv.c b/src/network/netdev/batadv.c index f42f572a367..15f3aee3a63 100644 --- a/src/network/netdev/batadv.c +++ b/src/network/netdev/batadv.c @@ -203,4 +203,5 @@ const NetDevVTable batadv_vtable = { .post_create = netdev_batadv_post_create, .create_type = NETDEV_CREATE_MASTER, .iftype = ARPHRD_ETHER, + .generate_mac = true, }; diff --git a/src/network/netdev/bridge.c b/src/network/netdev/bridge.c index 2d60e441ec3..64d65493caf 100644 --- a/src/network/netdev/bridge.c +++ b/src/network/netdev/bridge.c @@ -278,4 +278,5 @@ const NetDevVTable bridge_vtable = { .post_create = netdev_bridge_post_create, .create_type = NETDEV_CREATE_MASTER, .iftype = ARPHRD_ETHER, + .generate_mac = true, }; diff --git a/src/network/netdev/netdev-gperf.gperf b/src/network/netdev/netdev-gperf.gperf index d0f493b4ef5..316592005f2 100644 --- a/src/network/netdev/netdev-gperf.gperf +++ b/src/network/netdev/netdev-gperf.gperf @@ -49,7 +49,7 @@ NetDev.Description, config_parse_string, NetDev.Name, config_parse_ifname, 0, offsetof(NetDev, ifname) NetDev.Kind, config_parse_netdev_kind, 0, offsetof(NetDev, kind) NetDev.MTUBytes, config_parse_mtu, AF_UNSPEC, offsetof(NetDev, mtu) -NetDev.MACAddress, config_parse_hw_addr, ETH_ALEN, offsetof(NetDev, hw_addr) +NetDev.MACAddress, config_parse_netdev_hw_addr, ETH_ALEN, offsetof(NetDev, hw_addr) VLAN.Id, config_parse_vlanid, 0, offsetof(VLan, id) VLAN.Protocol, config_parse_vlanprotocol, 0, offsetof(VLan, protocol) VLAN.GVRP, config_parse_tristate, 0, offsetof(VLan, gvrp) @@ -111,7 +111,7 @@ L2TPSession.PeerSessionId, config_parse_l2tp_session_id, L2TPSession.Layer2SpecificHeader, config_parse_l2tp_session_l2spec, 0, 0 L2TPSession.Name, config_parse_l2tp_session_name, 0, 0 Peer.Name, config_parse_ifname, 0, offsetof(Veth, ifname_peer) -Peer.MACAddress, config_parse_hw_addr, ETH_ALEN, offsetof(Veth, hw_addr_peer) +Peer.MACAddress, config_parse_netdev_hw_addr, ETH_ALEN, offsetof(Veth, hw_addr_peer) VXCAN.Peer, config_parse_ifname, 0, offsetof(VxCan, ifname_peer) VXLAN.VNI, config_parse_uint32, 0, offsetof(VxLan, vni) VXLAN.Id, config_parse_uint32, 0, offsetof(VxLan, vni) /* deprecated */ diff --git a/src/network/netdev/netdev.c b/src/network/netdev/netdev.c index 2fd2659ddbb..5d88cbdf5f1 100644 --- a/src/network/netdev/netdev.c +++ b/src/network/netdev/netdev.c @@ -128,41 +128,6 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = { DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind); -int config_parse_netdev_kind( - const char *unit, - const char *filename, - unsigned line, - const char *section, - unsigned section_line, - const char *lvalue, - int ltype, - const char *rvalue, - void *data, - void *userdata) { - - NetDevKind k, *kind = data; - - assert(rvalue); - assert(data); - - k = netdev_kind_from_string(rvalue); - if (k < 0) { - log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue); - return 0; - } - - if (*kind != _NETDEV_KIND_INVALID && *kind != k) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s", - netdev_kind_to_string(*kind), rvalue); - return 0; - } - - *kind = k; - - return 0; -} - bool netdev_is_managed(NetDev *netdev) { if (!netdev || !netdev->manager || !netdev->ifname) return false; @@ -435,6 +400,9 @@ int netdev_generate_hw_addr(NetDev *netdev, const char *name, struct hw_addr_dat assert(name); assert(hw_addr); + if (hw_addr_equal(hw_addr, &HW_ADDR_NONE)) + return 0; + if (hw_addr->length == 0) { uint64_t result; @@ -502,7 +470,7 @@ static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handle if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_IFNAME, attribute: %m"); - if (netdev->hw_addr.length > 0) { + if (netdev->hw_addr.length > 0 && !hw_addr_equal(&netdev->hw_addr, &HW_ADDR_NULL)) { r = netlink_message_append_hw_addr(m, IFLA_ADDRESS, &netdev->hw_addr); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m"); @@ -886,3 +854,64 @@ int netdev_load(Manager *manager, bool reload) { return 0; } + +int config_parse_netdev_kind( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + NetDevKind k, *kind = data; + + assert(filename); + assert(rvalue); + assert(data); + + k = netdev_kind_from_string(rvalue); + if (k < 0) { + log_syntax(unit, LOG_WARNING, filename, line, k, "Failed to parse netdev kind, ignoring assignment: %s", rvalue); + return 0; + } + + if (*kind != _NETDEV_KIND_INVALID && *kind != k) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s", + netdev_kind_to_string(*kind), rvalue); + return 0; + } + + *kind = k; + + return 0; +} + +int config_parse_netdev_hw_addr( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + struct hw_addr_data *hw_addr = data; + + assert(rvalue); + assert(data); + + if (streq(rvalue, "none")) { + *hw_addr = HW_ADDR_NONE; + return 0; + } + + return config_parse_hw_addr(unit, filename, line, section, section_line, lvalue, ltype, rvalue, data, userdata); +} diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index d480d125a69..ed8a2e33c51 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -10,6 +10,9 @@ #include "networkd-link.h" #include "time-util.h" +/* Special hardware address value to suppress generating persistent hardware address for the netdev. */ +#define HW_ADDR_NONE ((struct hw_addr_data) { .length = 1, }) + #define NETDEV_COMMON_SECTIONS "Match\0NetDev\0" /* This is the list of known sections. We need to ignore them in the initial parsing phase. */ #define NETDEV_OTHER_SECTIONS \ @@ -215,6 +218,7 @@ static inline NetDevCreateType netdev_get_create_type(NetDev *netdev) { } CONFIG_PARSER_PROTOTYPE(config_parse_netdev_kind); +CONFIG_PARSER_PROTOTYPE(config_parse_netdev_hw_addr); /* gperf */ const struct ConfigPerfItem* network_netdev_gperf_lookup(const char *key, GPERF_LEN_TYPE length); diff --git a/src/network/netdev/veth.c b/src/network/netdev/veth.c index f1c05c62052..d7870d7628a 100644 --- a/src/network/netdev/veth.c +++ b/src/network/netdev/veth.c @@ -31,7 +31,7 @@ static int netdev_veth_fill_message_create(NetDev *netdev, Link *link, sd_netlin return log_netdev_error_errno(netdev, r, "Failed to add netlink interface name: %m"); } - if (v->hw_addr_peer.length > 0) { + if (v->hw_addr_peer.length > 0 && !hw_addr_equal(&v->hw_addr_peer, &HW_ADDR_NULL)) { r = netlink_message_append_hw_addr(m, IFLA_ADDRESS, &v->hw_addr_peer); if (r < 0) return log_netdev_error_errno(netdev, r, "Could not append IFLA_ADDRESS attribute: %m");