a8c905
From 4f47e35ee4026f24ee99a0bfa7ba5b2f24a92a02 Mon Sep 17 00:00:00 2001
a8c905
From: Yu Watanabe <watanabe.yu+github@gmail.com>
a8c905
Date: Mon, 16 Dec 2019 23:44:42 +0900
a8c905
Subject: [PATCH] udev: introduce AlternativeNamesPolicy= setting
a8c905
a8c905
(cherry picked from commit ef1d2c07f9567dfea8a4e012d8779a4ded2d9ae6)
a8c905
a8c905
Resolves: #1850986
a8c905
---
a8c905
 man/systemd.link.xml                 | 11 +++++
a8c905
 src/udev/net/link-config-gperf.gperf |  1 +
a8c905
 src/udev/net/link-config.c           | 62 ++++++++++++++++++++++++++--
a8c905
 src/udev/net/link-config.h           |  5 +++
a8c905
 4 files changed, 76 insertions(+), 3 deletions(-)
a8c905
a8c905
diff --git a/man/systemd.link.xml b/man/systemd.link.xml
a8c905
index c8ebb751ee..13dcce0879 100644
a8c905
--- a/man/systemd.link.xml
a8c905
+++ b/man/systemd.link.xml
a8c905
@@ -343,6 +343,17 @@
a8c905
           </para>
a8c905
         </listitem>
a8c905
       </varlistentry>
a8c905
+      <varlistentry>
a8c905
+        <term><varname>AlternativeNamesPolicy=</varname></term>
a8c905
+        <listitem>
a8c905
+          <para>A space-separated list of policies by which the interface's alternative names
a8c905
+          should be set. Each of the policies may fail, and all successful policies are used. The
a8c905
+          available policies are <literal>database</literal>, <literal>onboard</literal>,
a8c905
+          <literal>slot</literal>, <literal>path</literal>, and <literal>mac</literal>. If the
a8c905
+          kernel does not support the alternative names, then this setting will be ignored.
a8c905
+          </para>
a8c905
+        </listitem>
a8c905
+      </varlistentry>
a8c905
       <varlistentry>
a8c905
         <term><varname>AlternativeName=</varname></term>
a8c905
         <listitem>
a8c905
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
a8c905
index 913c754145..df8404e7b8 100644
a8c905
--- a/src/udev/net/link-config-gperf.gperf
a8c905
+++ b/src/udev/net/link-config-gperf.gperf
a8c905
@@ -35,6 +35,7 @@ Link.MACAddress,                 config_parse_hwaddr,        0,
a8c905
 Link.NamePolicy,                 config_parse_name_policy,   0,                             offsetof(link_config, name_policy)
a8c905
 Link.Name,                       config_parse_ifname,        0,                             offsetof(link_config, name)
a8c905
 Link.AlternativeName,            config_parse_ifnames,       1,                             offsetof(link_config, alternative_names)
a8c905
+Link.AlternativeNamesPolicy,     config_parse_alternative_names_policy, 0,                  offsetof(link_config, alternative_names_policy)
a8c905
 Link.Alias,                      config_parse_ifalias,       0,                             offsetof(link_config, alias)
a8c905
 Link.MTUBytes,                   config_parse_mtu,           AF_UNSPEC,                     offsetof(link_config, mtu)
a8c905
 Link.BitsPerSecond,              config_parse_si_size,       0,                             offsetof(link_config, speed)
a8c905
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
a8c905
index 8e88c8e5c4..6ceb4c698e 100644
a8c905
--- a/src/udev/net/link-config.c
a8c905
+++ b/src/udev/net/link-config.c
a8c905
@@ -69,6 +69,7 @@ static void link_config_free(link_config *link) {
a8c905
         free(link->name_policy);
a8c905
         free(link->name);
a8c905
         strv_free(link->alternative_names);
a8c905
+        free(link->alternative_names_policy);
a8c905
         free(link->alias);
a8c905
 
a8c905
         free(link);
a8c905
@@ -349,6 +350,7 @@ static int get_mac(struct udev_device *device, bool want_random,
a8c905
 
a8c905
 int link_config_apply(link_config_ctx *ctx, link_config *config,
a8c905
                       struct udev_device *device, const char **name) {
a8c905
+        _cleanup_strv_free_ char **altnames = NULL;
a8c905
         bool respect_predictable = false;
a8c905
         struct ether_addr generated_mac;
a8c905
         struct ether_addr *mac = NULL;
a8c905
@@ -473,11 +475,52 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
a8c905
         if (r < 0)
a8c905
                 return log_warning_errno(r, "Could not set Alias=, MACAddress= or MTU= on %s: %m", old_name);
a8c905
 
a8c905
-        r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, config->alternative_names);
a8c905
+        if (config->alternative_names) {
a8c905
+                altnames = strv_copy(config->alternative_names);
a8c905
+                if (!altnames)
a8c905
+                        return log_oom();
a8c905
+        }
a8c905
+
a8c905
+        if (config->alternative_names_policy)
a8c905
+                for (NamePolicy *p = config->alternative_names_policy; *p != _NAMEPOLICY_INVALID; p++) {
a8c905
+                        const char *n;
a8c905
+
a8c905
+                        switch (*p) {
a8c905
+                        case NAMEPOLICY_DATABASE:
a8c905
+                                n = udev_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE");
a8c905
+                                break;
a8c905
+                        case NAMEPOLICY_ONBOARD:
a8c905
+                                n = udev_device_get_property_value(device, "ID_NET_NAME_ONBOARD");
a8c905
+                                break;
a8c905
+                        case NAMEPOLICY_SLOT:
a8c905
+                                n = udev_device_get_property_value(device, "ID_NET_NAME_SLOT");
a8c905
+                                break;
a8c905
+                        case NAMEPOLICY_PATH:
a8c905
+                                n = udev_device_get_property_value(device, "ID_NET_NAME_PATH");
a8c905
+                                break;
a8c905
+                        case NAMEPOLICY_MAC:
a8c905
+                                n = udev_device_get_property_value(device, "ID_NET_NAME_MAC");
a8c905
+                                break;
a8c905
+                        default:
a8c905
+                                assert_not_reached("invalid policy");
a8c905
+                        }
a8c905
+                        if (!isempty(n)) {
a8c905
+                                r = strv_extend(&altnames, n);
a8c905
+                                if (r < 0)
a8c905
+                                        return log_oom();
a8c905
+                        }
a8c905
+                }
a8c905
+
a8c905
+        if (new_name)
a8c905
+                strv_remove(altnames, new_name);
a8c905
+        strv_remove(altnames, old_name);
a8c905
+        strv_uniq(altnames);
a8c905
+
a8c905
+        r = rtnl_set_link_alternative_names(&ctx->rtnl, ifindex, altnames);
a8c905
         if (r == -EOPNOTSUPP)
a8c905
-                log_debug_errno(r, "Could not set AlternativeName= on %s, ignoring: %m", old_name);
a8c905
+                log_debug_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s, ignoring: %m", old_name);
a8c905
         else if (r < 0)
a8c905
-                return log_warning_errno(r, "Could not set AlternativeName= on %s: %m", old_name);
a8c905
+                return log_warning_errno(r, "Could not set AlternativeName= or apply AlternativeNamesPolicy= on %s: %m", old_name);
a8c905
 
a8c905
         *name = new_name;
a8c905
 
a8c905
@@ -524,3 +567,16 @@ DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
a8c905
 DEFINE_CONFIG_PARSE_ENUMV(config_parse_name_policy, name_policy, NamePolicy,
a8c905
                           _NAMEPOLICY_INVALID,
a8c905
                           "Failed to parse interface name policy");
a8c905
+
a8c905
+static const char* const alternative_names_policy_table[_NAMEPOLICY_MAX] = {
a8c905
+        [NAMEPOLICY_DATABASE] = "database",
a8c905
+        [NAMEPOLICY_ONBOARD] = "onboard",
a8c905
+        [NAMEPOLICY_SLOT] = "slot",
a8c905
+        [NAMEPOLICY_PATH] = "path",
a8c905
+        [NAMEPOLICY_MAC] = "mac",
a8c905
+};
a8c905
+
a8c905
+DEFINE_STRING_TABLE_LOOKUP(alternative_names_policy, NamePolicy);
a8c905
+DEFINE_CONFIG_PARSE_ENUMV(config_parse_alternative_names_policy, alternative_names_policy, NamePolicy,
a8c905
+                          _NAMEPOLICY_INVALID,
a8c905
+                          "Failed to parse alternative names policy");
a8c905
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
a8c905
index 93d5fdce59..634bd2ec54 100644
a8c905
--- a/src/udev/net/link-config.h
a8c905
+++ b/src/udev/net/link-config.h
a8c905
@@ -49,6 +49,7 @@ struct link_config {
a8c905
         struct ether_addr *mac;
a8c905
         MACPolicy mac_policy;
a8c905
         NamePolicy *name_policy;
a8c905
+        NamePolicy *alternative_names_policy;
a8c905
         char *name;
a8c905
         char **alternative_names;
a8c905
         char *alias;
a8c905
@@ -78,6 +79,9 @@ int link_get_driver(link_config_ctx *ctx, struct udev_device *device, char **ret
a8c905
 const char *name_policy_to_string(NamePolicy p) _const_;
a8c905
 NamePolicy name_policy_from_string(const char *p) _pure_;
a8c905
 
a8c905
+const char *alternative_names_policy_to_string(NamePolicy p) _const_;
a8c905
+NamePolicy alternative_names_policy_from_string(const char *p) _pure_;
a8c905
+
a8c905
 const char *mac_policy_to_string(MACPolicy p) _const_;
a8c905
 MACPolicy mac_policy_from_string(const char *p) _pure_;
a8c905
 
a8c905
@@ -86,3 +90,4 @@ const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, GPERF_LEN
a8c905
 
a8c905
 int config_parse_mac_policy(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);
a8c905
 int config_parse_name_policy(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);
a8c905
+int config_parse_alternative_names_policy(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);