]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network, udev: introduce PermanentMACAddress= setting in [Match] section
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 7 Jan 2019 11:16:19 +0000 (20:16 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 8 Jan 2020 08:54:54 +0000 (17:54 +0900)
Closes #13983.

15 files changed:
man/systemd.link.xml
man/systemd.network.xml
src/libsystemd-network/network-internal.c
src/libsystemd-network/network-internal.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h
src/network/test-network.c
src/udev/net/link-config-gperf.gperf
src/udev/net/link-config.c
src/udev/net/link-config.h
test/fuzz/fuzz-link-parser/directives.link
test/fuzz/fuzz-network-parser/directives.network

index 2f231d497877800138057bb2b4c6c56862f0857e..1a405e989de17f3073f13c6286a97e374fe7889b 100644 (file)
           <programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>PermanentMACAddress=</varname></term>
+        <listitem>
+          <para>A whitespace-separated list of hardware's permanent addresses. While
+          <varname>MACAddress=</varname> matches the device's current MAC address, this matches the
+          device's permanent MAC address, which may be different from the current one. Use full
+          colon-, hyphen- or dot-delimited hexadecimal. This option may appear more than once, in
+          which case the lists are merged. If the empty string is assigned to this option, the list
+          of hardware addresses defined prior to this is reset.</para>
+        </listitem>
+      </varlistentry>
       <varlistentry>
         <term><varname>OriginalName=</varname></term>
         <listitem>
index 4cd25201737f2638c38c9cdb12017f6ae376422f..de1a854494bd5278da4793ce358571f11a2411f1 100644 (file)
             <programlisting>MACAddress=01:23:45:67:89:ab 00-11-22-33-44-55 AABB.CCDD.EEFF</programlisting></para>
           </listitem>
         </varlistentry>
+        <varlistentry>
+          <term><varname>PermanentMACAddress=</varname></term>
+          <listitem>
+            <para>A whitespace-separated list of hardware's permanent addresses. While
+            <varname>MACAddress=</varname> matches the device's current MAC address, this matches the
+            device's permanent MAC address, which may be different from the current one. Use full
+            colon-, hyphen- or dot-delimited hexadecimal. This option may appear more than once, in
+            which case the lists are merged. If the empty string is assigned to this option, the list
+            of hardware addresses defined prior to this is reset.</para>
+          </listitem>
+        </varlistentry>
         <varlistentry>
           <term><varname>Path=</varname></term>
           <listitem>
index 7198fe4775c43bdc02638a409802460ab440018c..0bf0b0e5526073196eaff3145bc9d7a485a5d075 100644 (file)
@@ -167,6 +167,7 @@ static const char *const wifi_iftype_table[NL80211_IFTYPE_MAX+1] = {
 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_TO_STRING(wifi_iftype, enum nl80211_iftype);
 
 bool net_match_config(Set *match_mac,
+                      Set *match_permanent_mac,
                       char * const *match_paths,
                       char * const *match_drivers,
                       char * const *match_types,
@@ -177,6 +178,7 @@ bool net_match_config(Set *match_mac,
                       Set *match_bssid,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
+                      const struct ether_addr *dev_permanent_mac,
                       const char *dev_name,
                       char * const *alternative_names,
                       enum nl80211_iftype wifi_iftype,
@@ -200,6 +202,12 @@ bool net_match_config(Set *match_mac,
         if (match_mac && (!dev_mac || !set_contains(match_mac, dev_mac)))
                 return false;
 
+        if (match_permanent_mac &&
+            (!dev_permanent_mac ||
+             ether_addr_is_null(dev_permanent_mac) ||
+             !set_contains(match_permanent_mac, dev_permanent_mac)))
+                return false;
+
         if (!net_condition_test_strv(match_paths, dev_path))
                 return false;
 
index a940b24a42414023ea59acb0eae86663bd30be58..dff6c8831a03679458ff8c1ee8d7bd61ee977c9b 100644 (file)
@@ -16,6 +16,7 @@
 #define LINK_BRIDGE_PORT_PRIORITY_MAX 63
 
 bool net_match_config(Set *match_mac,
+                      Set *match_permanent_mac,
                       char * const *match_path,
                       char * const *match_driver,
                       char * const *match_type,
@@ -26,6 +27,7 @@ bool net_match_config(Set *match_mac,
                       Set *match_bssid,
                       sd_device *device,
                       const struct ether_addr *dev_mac,
+                      const struct ether_addr *dev_permanent_mac,
                       const char *dev_name,
                       char * const *alternative_names,
                       enum nl80211_iftype wifi_iftype,
index 23d0ee675b007ba9a4c9496bfb337e783c9293e9..cd370bef57dc7bdf3679136ca2c644eeda20dde7 100644 (file)
@@ -12,6 +12,7 @@
 #include "dhcp-identifier.h"
 #include "dhcp-lease-internal.h"
 #include "env-file.h"
+#include "ethtool-util.h"
 #include "fd-util.h"
 #include "fileio.h"
 #include "ipvlan.h"
@@ -617,6 +618,11 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         if (r < 0)
                 log_link_debug_errno(link, r, "MAC address not found for new device, continuing without");
 
+        _cleanup_close_ int fd = -1;
+        r = ethtool_get_permanent_macaddr(&fd, link->ifname, &link->permanent_mac);
+        if (r < 0)
+                log_link_debug_errno(link, r, "Permanent MAC address not found for new device, continuing without: %m");
+
         r = sd_netlink_message_read_strv(message, IFLA_PROP_LIST, IFLA_ALT_IFNAME, &link->alternative_names);
         if (r < 0 && r != -ENODATA)
                 return r;
@@ -2961,7 +2967,7 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for
         }
 
         r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
-                        &link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
+                        &link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
         if (r == -ENOENT) {
                 link_enter_unmanaged(link);
                 return 0;
@@ -3093,7 +3099,7 @@ static int link_initialized_and_synced(Link *link) {
                         return r;
 
                 r = network_get(link->manager, link->sd_device, link->ifname, link->alternative_names,
-                                &link->mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
+                                &link->mac, &link->permanent_mac, link->wlan_iftype, link->ssid, &link->bssid, &network);
                 if (r == -ENOENT) {
                         link_enter_unmanaged(link);
                         return 0;
index 172e48338371d036e138eb669d3b11624bc610e7..33be6618284fe84583f61f784f74e7e9652a2822 100644 (file)
@@ -53,6 +53,7 @@ typedef struct Link {
         unsigned short iftype;
         char *state_file;
         struct ether_addr mac;
+        struct ether_addr permanent_mac;
         struct in6_addr ipv6ll_address;
         uint32_t mtu;
         sd_device *sd_device;
index ecb82c237fd0c4908984c5cc10d45a4011a1a86f..67b3789ee6c1e0de88fac93d6d2cbe6521a496be 100644 (file)
@@ -28,6 +28,7 @@ struct ConfigPerfItem;
 %includes
 %%
 Match.MACAddress,                       config_parse_hwaddrs,                            0,                             offsetof(Network, match_mac)
+Match.PermanentMACAddress,              config_parse_hwaddrs,                            0,                             offsetof(Network, match_permanent_mac)
 Match.Path,                             config_parse_match_strv,                         0,                             offsetof(Network, match_path)
 Match.Driver,                           config_parse_match_strv,                         0,                             offsetof(Network, match_driver)
 Match.Type,                             config_parse_match_strv,                         0,                             offsetof(Network, match_type)
index 40394eb76652e00b4824fca834054f3d5eb4846e..4fd48be52a023720088fa2312a39cb2e7731ca00 100644 (file)
@@ -160,10 +160,10 @@ int network_verify(Network *network) {
         assert(network);
         assert(network->filename);
 
-        if (set_isempty(network->match_mac) && strv_isempty(network->match_path) &&
-            strv_isempty(network->match_driver) && strv_isempty(network->match_type) &&
-            strv_isempty(network->match_name) && strv_isempty(network->match_property) &&
-            strv_isempty(network->match_ssid) && !network->conditions)
+        if (set_isempty(network->match_mac) && set_isempty(network->match_permanent_mac) &&
+            strv_isempty(network->match_path) && strv_isempty(network->match_driver) &&
+            strv_isempty(network->match_type) && strv_isempty(network->match_name) &&
+            strv_isempty(network->match_property) && strv_isempty(network->match_ssid) && !network->conditions)
                 log_warning("%s: No valid settings found in the [Match] section. "
                             "The file will match all interfaces. "
                             "If that is intended, please add Name=* in the [Match] section.",
@@ -601,6 +601,7 @@ static Network *network_free(Network *network) {
         free(network->filename);
 
         set_free_free(network->match_mac);
+        set_free_free(network->match_permanent_mac);
         strv_free(network->match_path);
         strv_free(network->match_driver);
         strv_free(network->match_type);
@@ -721,7 +722,8 @@ int network_get_by_name(Manager *manager, const char *name, Network **ret) {
 }
 
 int network_get(Manager *manager, sd_device *device,
-                const char *ifname, char * const *alternative_names, const struct ether_addr *address,
+                const char *ifname, char * const *alternative_names,
+                const struct ether_addr *address, const struct ether_addr *permanent_address,
                 enum nl80211_iftype wlan_iftype, const char *ssid, const struct ether_addr *bssid,
                 Network **ret) {
         Network *network;
@@ -731,10 +733,12 @@ int network_get(Manager *manager, sd_device *device,
         assert(ret);
 
         ORDERED_HASHMAP_FOREACH(network, manager->networks, i)
-                if (net_match_config(network->match_mac, network->match_path, network->match_driver,
+                if (net_match_config(network->match_mac, network->match_permanent_mac,
+                                     network->match_path, network->match_driver,
                                      network->match_type, network->match_name, network->match_property,
                                      network->match_wlan_iftype, network->match_ssid, network->match_bssid,
-                                     device, address, ifname, alternative_names, wlan_iftype, ssid, bssid)) {
+                                     device, address, permanent_address,
+                                     ifname, alternative_names, wlan_iftype, ssid, bssid)) {
                         if (network->match_name && device) {
                                 const char *attr;
                                 uint8_t name_assign_type = NET_NAME_UNKNOWN;
index 783f23c5dd09fa0d43fbef2a6420f01772bd597e..e1c1c17241df4ad937e5bff8be921af79ef6c0e2 100644 (file)
@@ -64,6 +64,7 @@ struct Network {
         unsigned n_ref;
 
         Set *match_mac;
+        Set *match_permanent_mac;
         char **match_path;
         char **match_driver;
         char **match_type;
@@ -302,7 +303,8 @@ int network_verify(Network *network);
 
 int network_get_by_name(Manager *manager, const char *name, Network **ret);
 int network_get(Manager *manager, sd_device *device, const char *ifname, char * const *alternative_names,
-                const struct ether_addr *mac, enum nl80211_iftype wlan_iftype, const char *ssid,
+                const struct ether_addr *mac, const struct ether_addr *permanent_mac,
+                enum nl80211_iftype wlan_iftype, const char *ssid,
                 const struct ether_addr *bssid, Network **ret);
 int network_apply(Network *network, Link *link);
 void network_apply_anonymize_if_set(Network *network);
index 9c068606990e0b835c88723be09163dc53ab772d..7c37563ac22ae0a694b97024dd48a79af1dcbf90 100644 (file)
@@ -125,7 +125,7 @@ static void test_network_get(Manager *manager, sd_device *loopback) {
 
         /* let's assume that the test machine does not have a .network file
            that applies to the loopback device... */
-        assert_se(network_get(manager, loopback, "lo", NULL, &mac, 0, NULL, NULL, &network) == -ENOENT);
+        assert_se(network_get(manager, loopback, "lo", NULL, &mac, &mac, 0, NULL, NULL, &network) == -ENOENT);
         assert_se(!network);
 }
 
index a1105fa6742c1b8279869b379d787da24c3a20bb..686ff1bc5ca9b71e876d8f57868bd5f34c2c9b76 100644 (file)
@@ -20,6 +20,7 @@ struct ConfigPerfItem;
 %includes
 %%
 Match.MACAddress,                config_parse_hwaddrs,                  0,                             offsetof(link_config, match_mac)
+Match.PermanentMACAddress,       config_parse_hwaddrs,                  0,                             offsetof(link_config, match_permanent_mac)
 Match.OriginalName,              config_parse_match_ifnames,            0,                             offsetof(link_config, match_name)
 Match.Path,                      config_parse_match_strv,               0,                             offsetof(link_config, match_path)
 Match.Driver,                    config_parse_match_strv,               0,                             offsetof(link_config, match_driver)
index d199d83411fa8c99254ffa347ddbfe7ebe36eaa4..4a44edfc014dc83bf66e7f9f02f8b419178556fc 100644 (file)
@@ -47,6 +47,7 @@ static void link_config_free(link_config *link) {
         free(link->filename);
 
         set_free_free(link->match_mac);
+        set_free_free(link->match_permanent_mac);
         strv_free(link->match_path);
         strv_free(link->match_driver);
         strv_free(link->match_type);
@@ -162,8 +163,8 @@ int link_load_one(link_config_ctx *ctx, const char *filename) {
         if (link->speed > UINT_MAX)
                 return -ERANGE;
 
-        if (set_isempty(link->match_mac) && strv_isempty(link->match_path) &&
-            strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
+        if (set_isempty(link->match_mac) && set_isempty(link->match_permanent_mac) &&
+            strv_isempty(link->match_path) && strv_isempty(link->match_driver) && strv_isempty(link->match_type) &&
             strv_isempty(link->match_name) && strv_isempty(link->match_property) && !link->conditions)
                 log_warning("%s: No valid settings found in the [Match] section. "
                             "The file will match all interfaces. "
@@ -236,16 +237,27 @@ bool link_config_should_reload(link_config_ctx *ctx) {
 }
 
 int link_config_get(link_config_ctx *ctx, sd_device *device, link_config **ret) {
+        struct ether_addr permanent_mac = {};
         link_config *link;
+        const char *name;
+        int r;
 
         assert(ctx);
         assert(device);
         assert(ret);
 
+        r = sd_device_get_sysname(device, &name);
+        if (r < 0)
+                return r;
+
+        r = ethtool_get_permanent_macaddr(&ctx->ethtool_fd, name, &permanent_mac);
+        if (r < 0)
+                log_device_debug_errno(device, r, "Failed to get permanent MAC address, ignoring: %m");
+
         LIST_FOREACH(links, link, ctx->links) {
-                if (net_match_config(link->match_mac, link->match_path, link->match_driver,
+                if (net_match_config(link->match_mac, link->match_permanent_mac, link->match_path, link->match_driver,
                                      link->match_type, link->match_name, link->match_property, NULL, NULL, NULL,
-                                     device, NULL, NULL, NULL, 0, NULL, NULL)) {
+                                     device, NULL, &permanent_mac, NULL, NULL, 0, NULL, NULL)) {
                         if (link->match_name && !strv_contains(link->match_name, "*")) {
                                 unsigned name_assign_type = NET_NAME_UNKNOWN;
 
index 1c3a3f7fd472f903746965055a09fcb55954a732..496a8bccb78c38a5928cae7e640d60f6f3ee2e57 100644 (file)
@@ -36,6 +36,7 @@ struct link_config {
         char *filename;
 
         Set *match_mac;
+        Set *match_permanent_mac;
         char **match_path;
         char **match_driver;
         char **match_type;
index abf21f678a881d23bf085b27dc8b087f1624ab04..ba8760f12bab808b87530ab8b4bfebaacc1d81ff 100644 (file)
@@ -1,5 +1,6 @@
 [Match]
 MACAddress=
+PermanentMACAddress=
 OriginalName=
 Path=
 Driver=
index 37d31e3a92e6134e47623cdbb2293d289532e691..0e3adac5ce1b6c45f61c7d502978d0ca5fc4c9e5 100644 (file)
@@ -28,6 +28,7 @@ Virtualization=
 KernelCommandLine=
 Host=
 MACAddress=
+PermanentMACAddress=
 [Link]
 RequiredForOnline=
 ARP=