]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network-generator: support to set NamePolicy= through kernel command line argument
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 14 Dec 2021 02:29:08 +0000 (11:29 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 15 Dec 2021 16:55:37 +0000 (01:55 +0900)
Closes #16296.

man/systemd-network-generator.service.xml
man/systemd-udevd.service.xml
src/network/generator/main.c
src/network/generator/network-generator.c
src/network/generator/network-generator.h

index 99a032179e629b3a8aeddfe6588189b20ba6ee2f..6b7e2564d46ae5f4f6df347c7debc6d9d16b047a 100644 (file)
@@ -59,6 +59,7 @@
 
       <varlistentry>
         <term><varname>ifname=</varname></term>
+        <term><varname>net.ifname-policy=</varname></term>
         <listitem>
           <para>— translated into
           <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry> files.</para>
@@ -88,6 +89,8 @@
 
     <para>See
     <citerefentry project='man-pages'><refentrytitle>dracut.kernel</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+    and
+    <citerefentry><refentrytitle>systemd-udevd.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
     for option syntax and details.</para>
   </refsect1>
 
index 32cb82bac304d1a5b04f824cd4e8b31dffa29ac4..1bc86469be905bce49ad257946817801e121becb 100644 (file)
           appear, which affects older name derivation algorithms, too.</para>
         </listitem>
       </varlistentry>
+      <varlistentry>
+        <term><varname>net.ifname-policy=<replaceable>policy1</replaceable>[,<replaceable>policy2</replaceable>,…][,<replaceable>MAC</replaceable>]</varname></term>
+        <listitem>
+          <para>Specifies naming policies applied when renaming network interfaces. Takes a list of
+          policies and an optional MAC address separated with comma. Each policy value must be one of
+          the policies understood by the <varname>NamePolicy=</varname> setting in .link files, e.g.
+          <literal>onboard</literal> or <literal>path</literal>. See
+          <citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+          for more details. When the MAC address is specified, the policies are applied to the
+          interface which has the address. When no MAC address is specified, the policies are applied
+          to all interfaces. This kernel command line argument can be specified multiple times. This
+          argument is not directly read from <command>systemd-udevd</command>, but read and converted
+          to a .link file by <command>systemd-network-generator</command>. So, to make this argument
+          take effect, <filename>systemd-network-generator.service</filename> must be enabled and
+          started before starting <filename>systemd-udevd.service</filename>. See
+          <citerefentry><refentrytitle>systemd-network-generator.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+          for more details about the service.</para>
+          <para>Example:
+          <programlisting>net.ifname-policy=keep,kernel,path,slot,onboard,01:23:45:67:89:ab
+net.ifname-policy=keep,kernel,path,slot,onboard,mac</programlisting>
+          This is mostly equivalent to creating the following .link files:
+          <programlisting># 91-name-policy-with-mac.link
+[Match]
+MACAddress=01:23:45:67:89:ab
+
+[Link]
+NamePolicy=keep kernel path slot onboard
+AlternativeNamePolicy=path slot onboard</programlisting>
+          and
+          <programlisting># 92-name-policy-for-all.link
+[Match]
+OriginalName=*
+
+[Link]
+NamePolicy=keep kernel path slot onboard mac
+AlternativeNamePolicy=path slot onboard mac</programlisting>
+          </para>
+        </listitem>
+      </varlistentry>
     </variablelist>
     <!-- when adding entries here, consider also adding them in kernel-command-line.xml -->
   </refsect1>
index 624b0a0b5dfda77e0d0b031336031ee939ccb34c..a36fe98c864a6192beed0af262bd9b68d7de154e 100644 (file)
@@ -65,9 +65,10 @@ static int link_save(Link *link, const char *dest_dir) {
 
         assert(link);
 
-        r = asprintf(&filename, "90-%s.link",
-                     link->ifname);
-        if (r < 0)
+        filename = strjoin(!isempty(link->ifname) ? "90" :
+                           !hw_addr_is_null(&link->mac) ? "91" : "92",
+                           "-", link->filename, ".link");
+        if (!filename)
                 return log_oom();
 
         r = generator_open_unit_file(dest_dir, "kernel command line", filename, &f);
@@ -104,7 +105,7 @@ static int context_save(Context *context) {
                         r = k;
         }
 
-        HASHMAP_FOREACH(link, context->links_by_name) {
+        HASHMAP_FOREACH(link, context->links_by_filename) {
                 k = link_save(link, p);
                 if (k < 0 && r >= 0)
                         r = k;
index 67480974e83f6bf656d28aa0b6f89c803f952b73..c081ec673c86a5b994f4370b0a099a293843817c 100644 (file)
@@ -5,6 +5,7 @@
 #include "hostname-util.h"
 #include "log.h"
 #include "macro.h"
+#include "netif-naming-scheme.h"
 #include "network-generator.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
@@ -25,6 +26,7 @@
 
   # .link
   ifname=<interface>:<MAC>
+  net.ifname-policy=policy1[,policy2,...][,<MAC>] # This is an original rule, not supported by other tools.
 
   # .netdev
   vlan=<vlanname>:<phydevice>
@@ -263,7 +265,10 @@ static Link *link_free(Link *link) {
         if (!link)
                 return NULL;
 
+        free(link->filename);
         free(link->ifname);
+        strv_free(link->policies);
+        strv_free(link->alt_policies);
         return mfree(link);
 }
 
@@ -276,28 +281,43 @@ static int link_new(
                 Link **ret) {
 
         _cleanup_(link_freep) Link *link = NULL;
-        _cleanup_free_ char *ifname = NULL;
+        _cleanup_free_ char *ifname = NULL, *filename = NULL;
         int r;
 
         assert(context);
+        assert(mac);
 
-        if (!ifname_valid(name))
-                return -EINVAL;
+        if (name) {
+                if (!ifname_valid(name))
+                        return -EINVAL;
 
-        ifname = strdup(name);
-        if (!ifname)
-                return -ENOMEM;
+                ifname = strdup(name);
+                if (!ifname)
+                        return -ENOMEM;
+
+                filename = strdup(name);
+                if (!filename)
+                        return -ENOMEM;
+        }
+
+        if (!filename) {
+                filename = strdup(hw_addr_is_null(mac) ? "default" :
+                                  HW_ADDR_TO_STR_FULL(mac, HW_ADDR_TO_STRING_NO_COLON));
+                if (!filename)
+                        return -ENOMEM;
+        }
 
         link = new(Link, 1);
         if (!link)
                 return -ENOMEM;
 
         *link = (Link) {
+                .filename = TAKE_PTR(filename),
                 .ifname = TAKE_PTR(ifname),
                 .mac = *mac,
         };
 
-        r = hashmap_ensure_put(&context->links_by_name, &string_hash_ops, link->ifname, link);
+        r = hashmap_ensure_put(&context->links_by_filename, &string_hash_ops, link->filename, link);
         if (r < 0)
                 return r;
 
@@ -308,8 +328,10 @@ static int link_new(
         return 0;
 }
 
-Link *link_get(Context *context, const char *ifname) {
-        return hashmap_get(context->links_by_name, ifname);
+Link *link_get(Context *context, const char *filename) {
+        assert(context);
+        assert(filename);
+        return hashmap_get(context->links_by_filename, filename);
 }
 
 static int network_set_dhcp_type(Context *context, const char *ifname, const char *dhcp_type) {
@@ -922,6 +944,65 @@ static int parse_cmdline_ifname(Context *context, const char *key, const char *v
         return link_new(context, name, &mac, NULL);
 }
 
+static int parse_cmdline_ifname_policy(Context *context, const char *key, const char *value) {
+        _cleanup_strv_free_ char **policies = NULL, **alt_policies = NULL;
+        struct hw_addr_data mac = HW_ADDR_NULL;
+        Link *link;
+        int r;
+
+        /* net.ifname-policy=policy1[,policy2,...][,<MAC>] */
+
+        if (proc_cmdline_value_missing(key, value))
+                return -EINVAL;
+
+        for (const char *q = value; ; ) {
+                _cleanup_free_ char *word = NULL;
+                NamePolicy p;
+
+                r = extract_first_word(&q, &word, ",", 0);
+                if (r == 0)
+                        break;
+                if (r < 0)
+                        return r;
+
+                p = name_policy_from_string(word);
+                if (p < 0) {
+                        r = parse_hw_addr(word, &mac);
+                        if (r < 0)
+                                return r;
+
+                        if (hw_addr_is_null(&mac))
+                                return -EINVAL;
+
+                        if (!isempty(q))
+                                return -EINVAL;
+
+                        break;
+                }
+
+                if (alternative_names_policy_from_string(word) >= 0) {
+                        r = strv_extend(&alt_policies, word);
+                        if (r < 0)
+                                return r;
+                }
+
+                r = strv_consume(&policies, TAKE_PTR(word));
+                if (r < 0)
+                        return r;
+        }
+
+        if (strv_isempty(policies))
+                return -EINVAL;
+
+        r = link_new(context, NULL, &mac, &link);
+        if (r < 0)
+                return r;
+
+        link->policies = TAKE_PTR(policies);
+        link->alt_policies = TAKE_PTR(alt_policies);
+        return 0;
+}
+
 int parse_cmdline_item(const char *key, const char *value, void *data) {
         Context *context = data;
 
@@ -944,6 +1025,8 @@ int parse_cmdline_item(const char *key, const char *value, void *data) {
                 return parse_cmdline_bond(context, key, value);
         if (streq(key, "ifname"))
                 return parse_cmdline_ifname(context, key, value);
+        if (streq(key, "net.ifname-policy"))
+                return parse_cmdline_ifname_policy(context, key, value);
 
         return 0;
 }
@@ -995,7 +1078,7 @@ void context_clear(Context *context) {
 
         hashmap_free_with_destructor(context->networks_by_name, network_free);
         hashmap_free_with_destructor(context->netdevs_by_name, netdev_free);
-        hashmap_free_with_destructor(context->links_by_name, link_free);
+        hashmap_free_with_destructor(context->links_by_filename, link_free);
 }
 
 static int address_dump(Address *address, FILE *f) {
@@ -1123,11 +1206,25 @@ void link_dump(Link *link, FILE *f) {
 
         if (!hw_addr_is_null(&link->mac))
                 fprintf(f, "MACAddress=%s\n", HW_ADDR_TO_STR(&link->mac));
+        else
+                fputs("OriginalName=*\n", f);
 
-        fprintf(f,
-                "\n[Link]\n"
-                "Name=%s\n",
-                link->ifname);
+        fputs("\n[Link]\n", f);
+
+        if (!isempty(link->ifname))
+                fprintf(f, "Name=%s\n", link->ifname);
+
+        if (!strv_isempty(link->policies)) {
+                fputs("NamePolicy=", f);
+                fputstrv(f, link->policies, " ", NULL);
+                fputc('\n', f);
+        }
+
+        if (!strv_isempty(link->alt_policies)) {
+                fputs("AlternativeNamesPolicy=", f);
+                fputstrv(f, link->alt_policies, " ", NULL);
+                fputc('\n', f);
+        }
 }
 
 int network_format(Network *network, char **ret) {
index deaa40f8f3542475f0b7d0d77118ca9236120bbc..dd0a58738b679df719552aa62da75ecce35d65d1 100644 (file)
@@ -81,17 +81,21 @@ struct NetDev {
 };
 
 struct Link {
+        char *filename;
+
         /* [Match] */
         struct hw_addr_data mac;
 
         /* [Link] */
         char *ifname;
+        char **policies;
+        char **alt_policies;
 };
 
 typedef struct Context {
         Hashmap *networks_by_name;
         Hashmap *netdevs_by_name;
-        Hashmap *links_by_name;
+        Hashmap *links_by_filename;
 } Context;
 
 int parse_cmdline_item(const char *key, const char *value, void *data);
@@ -106,6 +110,6 @@ NetDev *netdev_get(Context *context, const char *ifname);
 void netdev_dump(NetDev *netdev, FILE *f);
 int netdev_format(NetDev *netdev, char **ret);
 
-Link *link_get(Context *context, const char *ifname);
+Link *link_get(Context *context, const char *filename);
 void link_dump(Link *link, FILE *f);
 int link_format(Link *link, char **ret);