This is mostly equivalent to .link file's MACAddressPolicy=none.
<varlistentry>
<term><varname>MACAddress=</varname></term>
<listitem>
- <para>The MAC address to use for the device. For <literal>tun</literal> or <literal>tap</literal>
- devices, setting <varname>MACAddress=</varname> in the [NetDev] section is not
- supported. Please specify it in the [Link] section of the corresponding
+ <para>Specifies the MAC address to use for the device, or takes the special value
+ <literal>none</literal>. When <literal>none</literal>, <command>systemd-networkd</command>
+ does not request the MAC address for the device, and the kernel will assign a random MAC
+ address. For <literal>tun</literal>, <literal>tap</literal>, or <literal>l2tp</literal>
+ devices, the <varname>MACAddress=</varname> setting in the [NetDev] section is not
+ supported and will be ignored. Please specify it in the [Link] section of the corresponding
<citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>
file. If this option is not set, <literal>bridge</literal> and <literal>vlan</literal> devices
inherit the MAC address of the first slave device or the physical interface, respectively. For other
name and the
<citerefentry><refentrytitle>machine-id</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
</para>
+ <para>Note, even if <literal>none</literal> is specified, <command>systemd-udevd</command>
+ will assign the persistent MAC address for the device, as <filename>99-default.link</filename>
+ has <varname>MACAddressPolicy=persistent</varname>. So, it is also necessary to create a
+ custom .link file for the device, if the MAC address assignment is not desired.</para>
</listitem>
</varlistentry>
</variablelist>
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)
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 */
assert(name);
assert(hw_addr);
+ if (hw_addr_equal(hw_addr, &HW_ADDR_NONE))
+ return 0;
+
if (hw_addr->length == 0) {
uint64_t result;
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");
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);
+}
#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 \
}
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);
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");