]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
Merge pull request #11465 from poettering/daemon-bus-flush
authorLennart Poettering <lennart@poettering.net>
Fri, 18 Jan 2019 12:48:52 +0000 (13:48 +0100)
committerGitHub <noreply@github.com>
Fri, 18 Jan 2019 12:48:52 +0000 (13:48 +0100)
flush+close bus connections explicitly when our daemons go down

19 files changed:
NEWS
man/systemd.link.xml
man/systemd.xml
network/99-default.link
src/core/job.c
src/libsystemd-network/dhcp-identifier.c
src/login/pam_systemd.c
src/network/networkd-link.c
src/network/networkd-link.h
src/udev/meson.build
src/udev/net/link-config.c
src/udev/net/link-config.h
src/udev/net/naming-scheme.c [new file with mode: 0644]
src/udev/net/naming-scheme.h [new file with mode: 0644]
src/udev/udev-builtin-net_id.c
src/udev/udev-builtin.c
test/test-network/conf/25-route-ipv6-src.network [new file with mode: 0644]
test/test-network/systemd-networkd-tests.py
tools/choose-default-locale.sh

diff --git a/NEWS b/NEWS
index c76b571d2baf10a942a5459991b3e7b554331571..d44e51136f0221954d440576680ebf81f56dd3d7 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -22,6 +22,23 @@ CHANGES WITH 241 in spe:
         * $DBUS_SESSION_BUS_ADDRESS environment variable is set by pam_systemd
           again.
 
+        * A new network device NamePolicy "keep" is implemented for link files,
+          and used by default in 99-default.link (the fallback configuration
+          provided by systemd). With this policy, if the network device name
+          was already set by userspace, the device will not be renamed again.
+          This matches the naming scheme that was implemented before
+          systemd-240. If naming-scheme < 240 is specified, the "keep" policy
+          is also enabled by default, even if not specified. Effectively, this
+          means that if naming-scheme >= 240 is specified, network devices will
+          be renamed according to the configuration, even if they have been
+          renamed already, if "keep" is not specified as the naming policy in
+          the .link file. The 99-default.link file provided by systemd includes
+          "keep" for backwards compatibility, but it is recommended for user
+          installed .link files to *not* include it.
+
+          The "kernel" policy, which keeps kernel names declared to be
+          "persistent", now works again as documented.
+
         * kernel-install script now optionally takes a path to an initrd file,
           and passes it to all plugins.
 
@@ -509,6 +526,11 @@ CHANGES WITH 240:
         * $DBUS_SESSION_BUS_ADDRESS environment variable is not set by
           pam_systemd anymore.
 
+        * The naming scheme for network devices was changed to always rename
+          devices, even if they were already renamed by userspace. The "kernel"
+          policy was changed to only apply as a fallback, if no other naming
+          policy took effect.
+
         * The requirements to build systemd is bumped to meson-0.46 and
           python-3.5.
 
index ec0314dec3f8dc89f262797aceeb6026221a0895..178f9b81afce6439c1ce57d7e2042f9c58c6ed06 100644 (file)
     same name pointing to <filename>/dev/null</filename> disables the
     configuration file entirely (it is "masked").</para>
 
-    <para>The link file contains a <literal>[Match]</literal> section,
-    which determines if a given link file may be applied to a given
-    device, as well as a <literal>[Link]</literal> section specifying
-    how the device should be configured. The first (in lexical order)
-    of the link files that matches a given device is applied. Note
-    that a default file <filename>99-default.link</filename> is
-    shipped by the system. Any user-supplied
-    <filename>.link</filename> should hence have a lexically earlier
-    name to be considered at all.</para>
-
-    <para>See
-    <citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>
-    for diagnosing problems with <filename>.link</filename> files.</para>
+    <para>The link file contains a [Match] section, which determines if a given link file may be applied to a
+    given device, as well as a [Link] section specifying how the device should be configured. The first (in
+    lexical order) of the link files that matches a given device is applied. Note that a default file
+    <filename>99-default.link</filename> is shipped by the system. Any user-supplied
+    <filename>.link</filename> should hence have a lexically earlier name to be considered at all.</para>
+
+    <para>See <citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry> for
+    diagnosing problems with <filename>.link</filename> files.</para>
   </refsect1>
 
   <refsect1>
     <title>[Match] Section Options</title>
 
-    <para>A link file is said to match a device if each of the entries
-    in the <literal>[Match]</literal> section matches, or if the
-    section is empty. The following keys are accepted:</para>
+    <para>A link file is said to match a device if each of the entries in the [Match] section matches, or if
+    the section is empty. The following keys are accepted:</para>
 
     <variablelist class='network-directives'>
       <varlistentry>
         <listitem>
           <para>A whitespace-separated list of shell-style globs matching
           the persistent path, as exposed by the udev property
-          <literal>ID_PATH</literal>.</para>
+          <varname>ID_PATH</varname>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Driver=</varname></term>
         <listitem>
-          <para>A whitespace-separated list of shell-style globs matching
-          the driver currently bound to the device,
-          as exposed by the udev property <literal>DRIVER</literal>
-          of its parent device, or if that is not set, the
-          driver as exposed by <literal>ethtool -i</literal>
-          of the device itself.</para>
+          <para>A whitespace-separated list of shell-style globs matching the driver currently bound to the
+          device, as exposed by the udev property <varname>DRIVER</varname> of its parent device, or if that
+          is not set, the driver as exposed by <command>ethtool -i</command> of the device itself.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <listitem>
           <para>A whitespace-separated list of shell-style globs matching
           the device type, as exposed by the udev
-          property <literal>DEVTYPE</literal>.</para>
+          property <varname>DEVTYPE</varname>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>Host=</varname></term>
         <listitem>
           <para>Matches against the hostname or machine
-          ID of the host. See <literal>ConditionHost=</literal> in
+          ID of the host. See <varname>ConditionHost=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
           for details.</para>
         </listitem>
           <para>Checks whether the system is executed in
           a virtualized environment and optionally test
           whether it is a specific implementation. See
-          <literal>ConditionVirtualization=</literal> in
+          <varname>ConditionVirtualization=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
           for details.</para>
         </listitem>
         <listitem>
           <para>Checks whether a specific kernel command line option
           is set (or if prefixed with the exclamation mark unset). See
-          <literal>ConditionKernelCommandLine=</literal> in
+          <varname>ConditionKernelCommandLine=</varname> in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
           for details.</para>
         </listitem>
           <listitem>
             <para>Checks whether the kernel version (as reported by <command>uname -r</command>) matches a certain
             expression (or if prefixed with the exclamation mark does not match it). See
-            <literal>ConditionKernelVersion=</literal> in
+            <varname>ConditionKernelVersion=</varname> in
             <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
             details.
             </para>
         <term><varname>Architecture=</varname></term>
         <listitem>
           <para>Checks whether the system is running on a specific
-          architecture. See <literal>ConditionArchitecture=</literal>
+          architecture. See <varname>ConditionArchitecture=</varname>
           in
           <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>
           for details.</para>
   <refsect1>
     <title>[Link] Section Options</title>
 
-    <para>The <literal>[Link]</literal> section accepts the following
+    <para>The [Link] section accepts the following
     keys:</para>
 
     <variablelist class='network-directives'>
       <varlistentry>
         <term><varname>Alias=</varname></term>
         <listitem>
-          <para>The <literal>ifalias</literal> is set to this
-          value.</para>
+          <para>The <varname>ifalias</varname> interface property is set to this value.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
 
           <variablelist>
             <varlistentry>
-              <term><literal>persistent</literal></term>
+              <term><option>persistent</option></term>
               <listitem>
                 <para>If the hardware has a persistent MAC address, as
                 most hardware should, and if it is used by the kernel,
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>random</literal></term>
+              <term><option>random</option></term>
               <listitem>
                 <para>If the kernel is using a random MAC address,
                 nothing is done. Otherwise, a new address is randomly
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>none</literal></term>
+              <term><option>none</option></term>
               <listitem>
                 <para>Keeps the MAC address assigned by the kernel.</para>
               </listitem>
         <term><varname>MACAddress=</varname></term>
         <listitem>
           <para>The MAC address to use, if no
-          <literal>MACAddressPolicy=</literal>
+          <varname>MACAddressPolicy=</varname>
           is specified.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
         <term><varname>NamePolicy=</varname></term>
         <listitem>
-          <para>An ordered, space-separated list of policies by which
-          the interface name should be set.
-          <literal>NamePolicy</literal> may be disabled by specifying
-          <literal>net.ifnames=0</literal> on the kernel command line.
-          Each of the policies may fail, and the first successful one
-          is used. The name is not set directly, but is exported to
-          udev as the property <literal>ID_NET_NAME</literal>, which
-          is, by default, used by a udev rule to set
-          <literal>NAME</literal>. If the name has already been set by
-          userspace, no renaming is performed. The available policies
-          are:</para>
+          <para>An ordered, space-separated list of policies by which the interface name should be set.
+          <varname>NamePolicy=</varname> may be disabled by specifying <option>net.ifnames=0</option> on the
+          kernel command line.  Each of the policies may fail, and the first successful one is used. The name
+          is not set directly, but is exported to udev as the property <option>ID_NET_NAME</option>, which
+          is, by default, used by a udev rule to set <varname>NAME</varname>. The available policies are:
+          </para>
 
           <variablelist>
             <varlistentry>
-              <term><literal>kernel</literal></term>
+              <term><option>kernel</option></term>
               <listitem>
                 <para>If the kernel claims that the name it has set
                 for a device is predictable, then no renaming is
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>database</literal></term>
+              <term><option>database</option></term>
               <listitem>
                 <para>The name is set based on entries in the udev's
                 Hardware Database with the key
-                <literal>ID_NET_NAME_FROM_DATABASE</literal>.
+                <varname>ID_NET_NAME_FROM_DATABASE</varname>.
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>onboard</literal></term>
+              <term><option>onboard</option></term>
               <listitem>
                 <para>The name is set based on information given by
                 the firmware for on-board devices, as exported by the
-                udev property <literal>ID_NET_NAME_ONBOARD</literal>.
+                udev property <varname>ID_NET_NAME_ONBOARD</varname>.
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>slot</literal></term>
+              <term><option>slot</option></term>
               <listitem>
                 <para>The name is set based on information given by
                 the firmware for hot-plug devices, as exported by the
-                udev property <literal>ID_NET_NAME_SLOT</literal>.
+                udev property <varname>ID_NET_NAME_SLOT</varname>.
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>path</literal></term>
+              <term><option>path</option></term>
               <listitem>
                 <para>The name is set based on the device's physical
                 location, as exported by the udev property
-                <literal>ID_NET_NAME_PATH</literal>.</para>
+                <varname>ID_NET_NAME_PATH</varname>.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>mac</literal></term>
+              <term><option>mac</option></term>
               <listitem>
                 <para>The name is set based on the device's persistent
                 MAC address, as exported by the udev property
-                <literal>ID_NET_NAME_MAC</literal>.</para>
+                <varname>ID_NET_NAME_MAC</varname>.</para>
+              </listitem>
+            </varlistentry>
+            <varlistentry>
+              <term><option>keep</option></term>
+              <listitem>
+                <para>If the device already had a name given by userspace (as part of creation of the device
+                or a rename), keep it.</para>
               </listitem>
             </varlistentry>
           </variablelist>
       <varlistentry>
         <term><varname>Duplex=</varname></term>
         <listitem>
-          <para>The duplex mode to set for the device. The accepted
-          values are <literal>half</literal> and
-          <literal>full</literal>.</para>
+          <para>The duplex mode to set for the device. The accepted values are <option>half</option> and
+          <option>full</option>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
 
           <variablelist>
             <varlistentry>
-              <term><literal>phy</literal></term>
+              <term><option>phy</option></term>
               <listitem>
                 <para>Wake on PHY activity.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>unicast</literal></term>
+              <term><option>unicast</option></term>
               <listitem>
                 <para>Wake on unicast messages.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>multicast</literal></term>
+              <term><option>multicast</option></term>
               <listitem>
                 <para>Wake on multicast messages.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>broadcast</literal></term>
+              <term><option>broadcast</option></term>
               <listitem>
                 <para>Wake on broadcast messages.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>arp</literal></term>
+              <term><option>arp</option></term>
               <listitem>
                 <para>Wake on ARP.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>magic</literal></term>
+              <term><option>magic</option></term>
               <listitem>
                 <para>Wake on receipt of a magic packet.
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>secureon</literal></term>
+              <term><option>secureon</option></term>
               <listitem>
                 <para>Enable secureon(tm) password for MagicPacket(tm).
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>off</literal></term>
+              <term><option>off</option></term>
               <listitem>
                 <para>Never wake.</para>
               </listitem>
             </varlistentry>
           </variablelist>
 
-          <para>Defaults to <literal>off</literal>.</para>
+          <para>Defaults to <option>off</option>.</para>
         </listitem>
       </varlistentry>
       <varlistentry>
 
           <variablelist>
             <varlistentry>
-              <term><literal>tp</literal></term>
+              <term><option>tp</option></term>
               <listitem>
                 <para>An Ethernet interface using Twisted-Pair cable as the medium.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>aui</literal></term>
+              <term><option>aui</option></term>
               <listitem>
                 <para>Attachment Unit Interface (AUI). Normally used with hubs.
                 </para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>bnc</literal></term>
+              <term><option>bnc</option></term>
               <listitem>
                 <para>An Ethernet interface using BNC connectors and co-axial cable.</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>mii</literal></term>
+              <term><option>mii</option></term>
               <listitem>
                 <para>An Ethernet interface using a Media Independent Interface (MII).</para>
               </listitem>
             </varlistentry>
             <varlistentry>
-              <term><literal>fibre</literal></term>
+              <term><option>fibre</option></term>
               <listitem>
                 <para>An Ethernet interface using Optical Fibre as the medium.</para>
               </listitem>
                 <entry>Duplex Mode</entry>
               </row></thead>
               <tbody>
-
-                <row><entry><literal>10baset-half</literal></entry>
+                <row><entry><option>10baset-half</option></entry>
                 <entry>10</entry><entry>half</entry></row>
 
-                <row><entry><literal>10baset-full</literal></entry>
+                <row><entry><option>10baset-full</option></entry>
                 <entry>10</entry><entry>full</entry></row>
 
-                <row><entry><literal>100baset-half</literal></entry>
+                <row><entry><option>100baset-half</option></entry>
                 <entry>100</entry><entry>half</entry></row>
 
-                <row><entry><literal>100baset-full</literal></entry>
+                <row><entry><option>100baset-full</option></entry>
                 <entry>100</entry><entry>full</entry></row>
 
-                <row><entry><literal>1000baset-half</literal></entry>
+                <row><entry><option>1000baset-half</option></entry>
                 <entry>1000</entry><entry>half</entry></row>
 
-                <row><entry><literal>1000baset-full</literal></entry>
+                <row><entry><option>1000baset-full</option></entry>
                 <entry>1000</entry><entry>full</entry></row>
 
-                <row><entry><literal>10000baset-full</literal></entry>
+                <row><entry><option>10000baset-full</option></entry>
                 <entry>10000</entry><entry>full</entry></row>
 
-                <row><entry><literal>2500basex-full</literal></entry>
+                <row><entry><option>2500basex-full</option></entry>
                 <entry>2500</entry><entry>full</entry></row>
 
-                <row><entry><literal>1000basekx-full</literal></entry>
+                <row><entry><option>1000basekx-full</option></entry>
                 <entry>1000</entry><entry>full</entry></row>
 
-                <row><entry><literal>10000basekx4-full</literal></entry>
+                <row><entry><option>10000basekx4-full</option></entry>
                 <entry>10000</entry><entry>full</entry></row>
 
-                <row><entry><literal>10000basekr-full</literal></entry>
+                <row><entry><option>10000basekr-full</option></entry>
                 <entry>10000</entry><entry>full</entry></row>
 
-                <row><entry><literal>10000baser-fec</literal></entry>
+                <row><entry><option>10000baser-fec</option></entry>
                 <entry>10000</entry><entry>full</entry></row>
 
-                <row><entry><literal>20000basemld2-full</literal></entry>
+                <row><entry><option>20000basemld2-full</option></entry>
                 <entry>20000</entry><entry>full</entry></row>
 
-                <row><entry><literal>20000basekr2-full</literal></entry>
+                <row><entry><option>20000basekr2-full</option></entry>
                 <entry>20000</entry><entry>full</entry></row>
               </tbody>
             </tgroup>
index 680f800f7dc7b14e1364281dde18d3af7360811f..5287bdaba89a47a4c1af0f5f88b80cace01d52b3 100644 (file)
     means that before executing a requested operation, systemd will
     verify that it makes sense, fixing it if possible, and only
     failing if it really cannot work.</para>
-    
+
     <para>Note that transactions are generated independently of a unit's
     state at runtime, hence, for example, if a start job is requested on an
     already started unit, it will still generate a transaction and wake up any
index 561bf329e485f57e7714a90f4a3c961fd8869474..92fcbe83eab91751854094023ff4d9c602378c98 100644 (file)
@@ -8,5 +8,5 @@
 #  (at your option) any later version.
 
 [Link]
-NamePolicy=kernel database onboard slot path
+NamePolicy=keep kernel database onboard slot path
 MACAddressPolicy=persistent
index 5210ac1ea0bc7c3cf8233c8fcd7d8cf6bf1a3f41..cc55bd01b8ee2879395db80e638318ccf62596d9 100644 (file)
@@ -207,7 +207,7 @@ Job* job_install(Job *j) {
                                 job_merge_into_installed(uj, j);
                                 log_unit_debug(uj->unit,
                                                "Merged %s/%s into installed job %s/%s as %"PRIu32,
-                                               j->unit->id, job_type_to_string(j->type), uj->unit->id, 
+                                               j->unit->id, job_type_to_string(j->type), uj->unit->id,
                                                job_type_to_string(uj->type), uj->id);
                                 return uj;
                         } else {
index 07496adaa390f06555810d0cfb8ea5121b13c1c5..4221b9c5044e1b8e7dd949d03df4ae4a5171b342 100644 (file)
@@ -11,6 +11,7 @@
 #include "network-internal.h"
 #include "siphash24.h"
 #include "sparse-endian.h"
+#include "stdio-util.h"
 #include "virt.h"
 
 #define SYSTEMD_PEN    43793
@@ -169,10 +170,10 @@ int dhcp_identifier_set_iaid(
 
         if (detect_container() <= 0) {
                 /* not in a container, udev will be around */
-                char ifindex_str[2 + DECIMAL_STR_MAX(int)];
+                char ifindex_str[1 + DECIMAL_STR_MAX(int)];
                 int r;
 
-                sprintf(ifindex_str, "n%d", ifindex);
+                xsprintf(ifindex_str, "n%d", ifindex);
                 if (sd_device_new_from_device_id(&device, ifindex_str) >= 0) {
                         r = sd_device_get_is_initialized(device);
                         if (r < 0)
index 0600c179d55f34a48015767e51d194dc7cb3091c..997b74eb88a917df2f64d334a4c02f4d018da85f 100644 (file)
@@ -28,6 +28,7 @@
 #include "path-util.h"
 #include "process-util.h"
 #include "socket-util.h"
+#include "stdio-util.h"
 #include "strv.h"
 #include "terminal-util.h"
 #include "util.h"
@@ -195,13 +196,30 @@ static int export_legacy_dbus_address(
                 uid_t uid,
                 const char *runtime) {
 
-        _cleanup_free_ char *s = NULL;
+        const char *s;
+        _cleanup_free_ char *t = NULL;
         int r = PAM_BUF_ERR;
 
-        if (asprintf(&s, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
+        /* We need to export $DBUS_SESSION_BUS_ADDRESS because various applications will not connect
+         * correctly to the bus without it. This setting matches what dbus.socket does for the user
+         * session using 'systemctl --user set-environment'. We want to have the same configuration
+         * in processes started from the PAM session.
+         *
+         * The setting of the address is guarded by the access() check because it is also possible to compile
+         * dbus without --enable-user-session, in which case this socket is not used, and
+         * $DBUS_SESSION_BUS_ADDRESS should not be set. An alternative approach would to not do the access()
+         * check here, and let applications try on their own, by using "unix:path=%s/bus;autolaunch:". But we
+         * expect the socket to be present by the time we do this check, so we can just as well check once
+         * here. */
+
+        s = strjoina(runtime, "/bus");
+        if (access(s, F_OK) < 0)
+                return PAM_SUCCESS;
+
+        if (asprintf(&t, DEFAULT_USER_BUS_ADDRESS_FMT, runtime) < 0)
                 goto error;
 
-        r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", s, 0);
+        r = pam_misc_setenv(handle, "DBUS_SESSION_BUS_ADDRESS", t, 0);
         if (r != PAM_SUCCESS)
                 goto error;
 
@@ -414,11 +432,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
 
         pam_get_item(handle, PAM_SERVICE, (const void**) &service);
         if (streq_ptr(service, "systemd-user")) {
-                _cleanup_free_ char *rt = NULL;
-
-                if (asprintf(&rt, "/run/user/"UID_FMT, pw->pw_uid) < 0)
-                        return PAM_BUF_ERR;
+                char rt[STRLEN("/run/user/") + DECIMAL_STR_MAX(uid_t)];
 
+                xsprintf(rt, "/run/user/"UID_FMT, pw->pw_uid);
                 if (validate_runtime_directory(handle, rt, pw->pw_uid)) {
                         r = pam_misc_setenv(handle, "XDG_RUNTIME_DIR", rt, 0);
                         if (r != PAM_SUCCESS) {
index 3661498f391d4c2919fa1b82a9ab8a33dd85ac12..ae0fc8403e8fda30f67cebf228cef2d4756088c1 100644 (file)
@@ -728,63 +728,6 @@ static void link_enter_configured(Link *link) {
         link_dirty(link);
 }
 
-void link_check_ready(Link *link) {
-        Address *a;
-        Iterator i;
-
-        assert(link);
-
-        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
-                return;
-
-        if (!link->network)
-                return;
-
-        if (!link->addresses_configured)
-                return;
-
-        if (!link->neighbors_configured)
-                return;
-
-        if (!link->static_routes_configured)
-                return;
-
-        if (!link->routing_policy_rules_configured)
-                return;
-
-        if (link_ipv4ll_enabled(link))
-                if (!link->ipv4ll_address ||
-                    !link->ipv4ll_route)
-                        return;
-
-        if (!link->network->bridge) {
-
-                if (link_ipv6ll_enabled(link))
-                        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
-                                return;
-
-                if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
-                     !link->dhcp4_configured) ||
-                    (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
-                     !link->dhcp6_configured) ||
-                    (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
-                     !link->dhcp4_configured && !link->dhcp6_configured))
-                        return;
-
-                if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
-                        return;
-        }
-
-        SET_FOREACH(a, link->addresses, i)
-                if (!address_is_ready(a))
-                        return;
-
-        if (link->state != LINK_STATE_CONFIGURED)
-                link_enter_configured(link);
-
-        return;
-}
-
 static int link_request_set_routing_policy_rule(Link *link) {
         RoutingPolicyRule *rule, *rrule = NULL;
         int r;
@@ -898,6 +841,68 @@ static int link_request_set_routes(Link *link) {
         return 0;
 }
 
+void link_check_ready(Link *link) {
+        Address *a;
+        Iterator i;
+
+        assert(link);
+
+        if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
+                return;
+
+        if (!link->network)
+                return;
+
+        if (!link->addresses_configured)
+                return;
+
+        if (!link->neighbors_configured)
+                return;
+
+        SET_FOREACH(a, link->addresses, i)
+                if (!address_is_ready(a))
+                        return;
+
+        if (!link->addresses_ready) {
+                link->addresses_ready = true;
+                link_request_set_routes(link);
+        }
+
+        if (!link->static_routes_configured)
+                return;
+
+        if (!link->routing_policy_rules_configured)
+                return;
+
+        if (link_ipv4ll_enabled(link))
+                if (!link->ipv4ll_address ||
+                    !link->ipv4ll_route)
+                        return;
+
+        if (!link->network->bridge) {
+
+                if (link_ipv6ll_enabled(link))
+                        if (in_addr_is_null(AF_INET6, (const union in_addr_union*) &link->ipv6ll_address) > 0)
+                                return;
+
+                if ((link_dhcp4_enabled(link) && !link_dhcp6_enabled(link) &&
+                     !link->dhcp4_configured) ||
+                    (link_dhcp6_enabled(link) && !link_dhcp4_enabled(link) &&
+                     !link->dhcp6_configured) ||
+                    (link_dhcp4_enabled(link) && link_dhcp6_enabled(link) &&
+                     !link->dhcp4_configured && !link->dhcp6_configured))
+                        return;
+
+                if (link_ipv6_accept_ra_enabled(link) && !link->ndisc_configured)
+                        return;
+        }
+
+        if (link->state != LINK_STATE_CONFIGURED)
+                link_enter_configured(link);
+
+        return;
+}
+
 static int link_request_set_neighbors(Link *link) {
         Neighbor *neighbor;
         int r;
@@ -952,7 +957,7 @@ static int address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link)
         if (link->address_messages == 0) {
                 log_link_debug(link, "Addresses set");
                 link->addresses_configured = true;
-                link_request_set_routes(link);
+                link_check_ready(link);
         }
 
         return 1;
@@ -1082,6 +1087,7 @@ static int link_request_set_addresses(Link *link) {
 
         /* Reset all *_configured flags we are configuring. */
         link->addresses_configured = false;
+        link->addresses_ready = false;
         link->neighbors_configured = false;
         link->static_routes_configured = false;
         link->routing_policy_rules_configured = false;
@@ -1236,7 +1242,7 @@ static int link_request_set_addresses(Link *link) {
 
         if (link->address_messages == 0) {
                 link->addresses_configured = true;
-                link_request_set_routes(link);
+                link_check_ready(link);
         } else
                 log_link_debug(link, "Setting addresses");
 
index 00e68fdfaab6975d753acc4eee9b52ec0f3368bb..e417ea26ef3089ca177635f20da7530dbb7e0820 100644 (file)
@@ -82,6 +82,7 @@ typedef struct Link {
         Set *routes_foreign;
 
         bool addresses_configured;
+        bool addresses_ready;
 
         sd_dhcp_client *dhcp_client;
         sd_dhcp_lease *dhcp_lease;
index a9d6c6363f20077ca7ebedb50604a78d6b64398a..9d3f6d1c5624447c48e3983ffdd0ab792162c5ff 100644 (file)
@@ -41,6 +41,8 @@ libudev_core_sources = '''
         net/link-config.h
         net/ethtool-util.c
         net/ethtool-util.h
+        net/naming-scheme.c
+        net/naming-scheme.h
 '''.split()
 
 if conf.get('HAVE_KMOD') == 1
index 537cc0cdd998c0b5966efe46e9a6890eacafc92c..eb2477cea418b37c07bcda5d7d3b6a079741cf15 100644 (file)
@@ -14,6 +14,7 @@
 #include "link-config.h"
 #include "log.h"
 #include "missing_network.h"
+#include "naming-scheme.h"
 #include "netlink-util.h"
 #include "network-internal.h"
 #include "parse-util.h"
@@ -186,6 +187,22 @@ static bool enable_name_policy(void) {
         return proc_cmdline_get_bool("net.ifnames", &b) <= 0 || b;
 }
 
+static int link_name_type(sd_device *device, unsigned *type) {
+        const char *s;
+        int r;
+
+        r = sd_device_get_sysattr_value(device, "name_assign_type", &s);
+        if (r < 0)
+                return log_device_debug_errno(device, r, "Failed to query name_assign_type: %m");
+
+        r = safe_atou(s, type);
+        if (r < 0)
+                return log_device_warning_errno(device, r, "Failed to parse name_assign_type \"%s\": %m", s);
+
+        log_device_debug(device, "Device has name_assign_type=%d", *type);
+        return 0;
+}
+
 int link_config_load(link_config_ctx *ctx) {
         _cleanup_strv_free_ char **files;
         char **f;
@@ -296,31 +313,6 @@ static bool mac_is_random(sd_device *device) {
         return type == NET_ADDR_RANDOM;
 }
 
-static bool should_rename(sd_device *device, bool respect_predictable) {
-        const char *s;
-        unsigned type;
-        int r;
-
-        /* if we can't get the assign type, assume we should rename */
-        if (sd_device_get_sysattr_value(device, "name_assign_type", &s) < 0)
-                return true;
-
-        r = safe_atou(s, &type);
-        if (r < 0)
-                return true;
-
-        switch (type) {
-        case NET_NAME_PREDICTABLE:
-                /* the kernel claims to have given a predictable name */
-                if (respect_predictable)
-                        return false;
-                _fallthrough_;
-        default:
-                /* the name is known to be bad, or of an unknown type */
-                return true;
-        }
-}
-
 static int get_mac(sd_device *device, bool want_random,
                    struct ether_addr *mac) {
         int r;
@@ -347,12 +339,12 @@ static int get_mac(sd_device *device, bool want_random,
 
 int link_config_apply(link_config_ctx *ctx, link_config *config,
                       sd_device *device, const char **name) {
-        bool respect_predictable = false;
         struct ether_addr generated_mac;
         struct ether_addr *mac = NULL;
         const char *new_name = NULL;
         const char *old_name;
-        unsigned speed;
+        unsigned speed, name_type = NET_NAME_UNKNOWN;
+        NamePolicy policy;
         int r, ifindex;
 
         assert(ctx);
@@ -405,38 +397,63 @@ int link_config_apply(link_config_ctx *ctx, link_config *config,
         if (r < 0)
                 return log_device_warning_errno(device, r, "Could not find ifindex: %m");
 
-        if (ctx->enable_name_policy && config->name_policy) {
-                NamePolicy *policy;
 
-                for (policy = config->name_policy;
-                     !new_name && *policy != _NAMEPOLICY_INVALID; policy++) {
-                        switch (*policy) {
-                                case NAMEPOLICY_KERNEL:
-                                        respect_predictable = true;
-                                        break;
-                                case NAMEPOLICY_DATABASE:
-                                        (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
-                                        break;
-                                case NAMEPOLICY_ONBOARD:
-                                        (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
-                                        break;
-                                case NAMEPOLICY_SLOT:
-                                        (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
-                                        break;
-                                case NAMEPOLICY_PATH:
-                                        (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
-                                        break;
-                                case NAMEPOLICY_MAC:
-                                        (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
-                                        break;
-                                default:
-                                        break;
+        (void) link_name_type(device, &name_type);
+
+        if (IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED)
+            && !naming_scheme_has(NAMING_ALLOW_RERENAMES)) {
+                log_device_debug(device, "Device already has a name given by userspace, not renaming.");
+                goto no_rename;
+        }
+
+        if (ctx->enable_name_policy && config->name_policy)
+                for (NamePolicy *p = config->name_policy; !new_name && *p != _NAMEPOLICY_INVALID; p++) {
+                        policy = *p;
+
+                        switch (policy) {
+                        case NAMEPOLICY_KERNEL:
+                                if (name_type != NET_NAME_PREDICTABLE)
+                                        continue;
+
+                                /* The kernel claims to have given a predictable name, keep it. */
+                                log_device_debug(device, "Policy *%s*: keeping predictable kernel name",
+                                                 name_policy_to_string(policy));
+                                goto no_rename;
+                        case NAMEPOLICY_KEEP:
+                                if (!IN_SET(name_type, NET_NAME_USER, NET_NAME_RENAMED))
+                                        continue;
+
+                                log_device_debug(device, "Policy *%s*: keeping existing userspace name",
+                                                 name_policy_to_string(policy));
+                                goto no_rename;
+                        case NAMEPOLICY_DATABASE:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_FROM_DATABASE", &new_name);
+                                break;
+                        case NAMEPOLICY_ONBOARD:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_ONBOARD", &new_name);
+                                break;
+                        case NAMEPOLICY_SLOT:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_SLOT", &new_name);
+                                break;
+                        case NAMEPOLICY_PATH:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_PATH", &new_name);
+                                break;
+                        case NAMEPOLICY_MAC:
+                                (void) sd_device_get_property_value(device, "ID_NET_NAME_MAC", &new_name);
+                                break;
+                        default:
+                                assert_not_reached("invalid policy");
                         }
                 }
-        }
 
-        if (!new_name && should_rename(device, respect_predictable))
+        if (new_name)
+                log_device_debug(device, "Policy *%s* yields \"%s\".", name_policy_to_string(policy), new_name);
+        else if (config->name) {
                 new_name = config->name;
+                log_device_debug(device, "Policies didn't yield a name, using specified Name=%s.", new_name);
+        } else
+                log_device_debug(device, "Policies didn't yield a name and Name= is not given, not renaming.");
+ no_rename:
 
         switch (config->mac_policy) {
                 case MACPOLICY_PERSISTENT:
@@ -495,7 +512,7 @@ int link_get_driver(link_config_ctx *ctx, sd_device *device, char **ret) {
 static const char* const mac_policy_table[_MACPOLICY_MAX] = {
         [MACPOLICY_PERSISTENT] = "persistent",
         [MACPOLICY_RANDOM] = "random",
-        [MACPOLICY_NONE] = "none"
+        [MACPOLICY_NONE] = "none",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(mac_policy, MACPolicy);
@@ -504,11 +521,12 @@ DEFINE_CONFIG_PARSE_ENUM(config_parse_mac_policy, mac_policy, MACPolicy,
 
 static const char* const name_policy_table[_NAMEPOLICY_MAX] = {
         [NAMEPOLICY_KERNEL] = "kernel",
+        [NAMEPOLICY_KEEP] = "keep",
         [NAMEPOLICY_DATABASE] = "database",
         [NAMEPOLICY_ONBOARD] = "onboard",
         [NAMEPOLICY_SLOT] = "slot",
         [NAMEPOLICY_PATH] = "path",
-        [NAMEPOLICY_MAC] = "mac"
+        [NAMEPOLICY_MAC] = "mac",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(name_policy, NamePolicy);
index 820495903462d7873532658be6d890b894c0e769..1113b1052e7d752b0ea5a3a673b101bc0c2da199 100644 (file)
@@ -22,6 +22,7 @@ typedef enum MACPolicy {
 
 typedef enum NamePolicy {
         NAMEPOLICY_KERNEL,
+        NAMEPOLICY_KEEP,
         NAMEPOLICY_DATABASE,
         NAMEPOLICY_ONBOARD,
         NAMEPOLICY_SLOT,
diff --git a/src/udev/net/naming-scheme.c b/src/udev/net/naming-scheme.c
new file mode 100644 (file)
index 0000000..27cede5
--- /dev/null
@@ -0,0 +1,64 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#include "alloc-util.h"
+#include "naming-scheme.h"
+#include "proc-cmdline.h"
+#include "string-util.h"
+
+static const NamingScheme naming_schemes[] = {
+        { "v238", NAMING_V238 },
+        { "v239", NAMING_V239 },
+        { "v240", NAMING_V240 },
+        /* … add more schemes here, as the logic to name devices is updated … */
+};
+
+static const NamingScheme* naming_scheme_from_name(const char *name) {
+        size_t i;
+
+        if (streq(name, "latest"))
+                return naming_schemes + ELEMENTSOF(naming_schemes) - 1;
+
+        for (i = 0; i < ELEMENTSOF(naming_schemes); i++)
+                if (streq(naming_schemes[i].name, name))
+                        return naming_schemes + i;
+
+        return NULL;
+}
+
+const NamingScheme* naming_scheme(void) {
+        static const NamingScheme *cache = NULL;
+        _cleanup_free_ char *buffer = NULL;
+        const char *e, *k;
+
+        if (cache)
+                return cache;
+
+        /* Acquire setting from the kernel command line */
+        (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer);
+
+        /* Also acquire it from an env var */
+        e = getenv("NET_NAMING_SCHEME");
+        if (e) {
+                if (*e == ':') {
+                        /* If prefixed with ':' the kernel cmdline takes precedence */
+                        k = buffer ?: e + 1;
+                } else
+                        k = e; /* Otherwise the env var takes precedence */
+        } else
+                k = buffer;
+
+        if (k) {
+                cache = naming_scheme_from_name(k);
+                if (cache) {
+                        log_info("Using interface naming scheme '%s'.", cache->name);
+                        return cache;
+                }
+
+                log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k);
+        }
+
+        cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME);
+        assert(cache);
+        log_info("Using default interface naming scheme '%s'.", cache->name);
+
+        return cache;
+}
diff --git a/src/udev/net/naming-scheme.h b/src/udev/net/naming-scheme.h
new file mode 100644 (file)
index 0000000..0b3d9bf
--- /dev/null
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: LGPL-2.1+ */
+#pragma once
+
+#include <stdbool.h>
+
+#include "macro.h"
+
+/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we
+ * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are
+ * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out
+ * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new
+ * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via
+ * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow:
+ * installers could "freeze" the used scheme at the moment of installation this way.
+ *
+ * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with
+ * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags.
+ *
+ * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the
+ * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually
+ * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across
+ * OS versions, but not fully stabilize them. */
+typedef enum NamingSchemeFlags {
+        /* First, the individual features */
+        NAMING_SR_IOV_V        = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/
+        NAMING_NPAR_ARI        = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */
+        NAMING_INFINIBAND      = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */
+        NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */
+        NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
+
+        /* And now the masks that combine the features above */
+        NAMING_V238 = 0,
+        NAMING_V239 = NAMING_V238 | NAMING_SR_IOV_V | NAMING_NPAR_ARI,
+        NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES,
+
+        _NAMING_SCHEME_FLAGS_INVALID = -1,
+} NamingSchemeFlags;
+
+typedef struct NamingScheme {
+        const char *name;
+        NamingSchemeFlags flags;
+} NamingScheme;
+
+const NamingScheme* naming_scheme(void);
+
+static inline bool naming_scheme_has(NamingSchemeFlags flags) {
+        return FLAGS_SET(naming_scheme()->flags, flags);
+}
index e4d40b149cc649ac7eef63bf40b5e36647d75678..03b281a77102c0e1228a79ccf9b431670958b0be 100644 (file)
 #include "fd-util.h"
 #include "fileio.h"
 #include "fs-util.h"
+#include "naming-scheme.h"
 #include "parse-util.h"
 #include "proc-cmdline.h"
 #include "stdio-util.h"
 
 #define ONBOARD_INDEX_MAX (16*1024-1)
 
-/* So here's the deal: net_id is supposed to be an excercise in providing stable names for network devices. However, we
- * also want to keep updating the naming scheme used in future versions of net_id. These two goals of course are
- * contradictory: on one hand we want things to not change and on the other hand we want them to improve. Our way out
- * of this dilemma is to introduce the "naming scheme" concept: each time we improve the naming logic we define a new
- * flag for it. Then, we keep a list of schemes, each identified by a name associated with the flags it implements. Via
- * a kernel command line and environment variable we then allow the user to pick the scheme they want us to follow:
- * installers could "freeze" the used scheme at the moment of installation this way.
- *
- * Developers: each time you tweak the naming logic here, define a new flag below, and condition the tweak with
- * it. Each time we do a release we'll then add a new scheme entry and include all newly defined flags.
- *
- * Note that this is only half a solution to the problem though: not only udev/net_id gets updated all the time, the
- * kernel gets too. And thus a kernel that previously didn't expose some sysfs attribute we look for might eventually
- * do, and thus affect our naming scheme too. Thus, enforcing a naming scheme will make interfacing more stable across
- * OS versions, but not fully stabilize them. */
-typedef enum NamingSchemeFlags {
-        /* First, the individual features */
-        NAMING_SR_IOV_V        = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a40008b8299529c978ed8e11de8f6*/
-        NAMING_NPAR_ARI        = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6eab35d1cb9fa73889892702c27be09 */
-        NAMING_INFINIBAND      = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df887797c9e05074a562ddacdcdf5e */
-        NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Allow zero acpi_index field, see d81186ef4f6a888a70f20a1e73a812d6acb9e22f */
-
-        /* And now the masks that combine the features above */
-        NAMING_V238 = 0,
-        NAMING_V239 = NAMING_V238|NAMING_SR_IOV_V|NAMING_NPAR_ARI,
-        NAMING_V240 = NAMING_V239|NAMING_INFINIBAND|NAMING_ZERO_ACPI_INDEX,
-
-        _NAMING_SCHEME_FLAGS_INVALID = -1,
-} NamingSchemeFlags;
-
-typedef struct NamingScheme {
-        const char *name;
-        NamingSchemeFlags flags;
-} NamingScheme;
-
-static const NamingScheme naming_schemes[] = {
-        { "v238", NAMING_V238 },
-        { "v239", NAMING_V239 },
-        { "v240", NAMING_V240 },
-        /* … add more schemes here, as the logic to name devices is updated … */
-};
-
 enum netname_type{
         NET_UNDEF,
         NET_PCI,
@@ -193,62 +152,6 @@ struct virtfn_info {
         char suffix[IFNAMSIZ];
 };
 
-static const NamingScheme* naming_scheme_from_name(const char *name) {
-        size_t i;
-
-        if (streq(name, "latest"))
-                return naming_schemes + ELEMENTSOF(naming_schemes) - 1;
-
-        for (i = 0; i < ELEMENTSOF(naming_schemes); i++)
-                if (streq(naming_schemes[i].name, name))
-                        return naming_schemes + i;
-
-        return NULL;
-}
-
-static const NamingScheme* naming_scheme(void) {
-        static const NamingScheme *cache = NULL;
-        _cleanup_free_ char *buffer = NULL;
-        const char *e, *k;
-
-        if (cache)
-                return cache;
-
-        /* Acquire setting from the kernel command line */
-        (void) proc_cmdline_get_key("net.naming-scheme", 0, &buffer);
-
-        /* Also acquire it from an env var */
-        e = getenv("NET_NAMING_SCHEME");
-        if (e) {
-                if (*e == ':') {
-                        /* If prefixed with ':' the kernel cmdline takes precedence */
-                        k = buffer ?: e + 1;
-                } else
-                        k = e; /* Otherwise the env var takes precedence */
-        } else
-                k = buffer;
-
-        if (k) {
-                cache = naming_scheme_from_name(k);
-                if (cache) {
-                        log_info("Using interface naming scheme '%s'.", cache->name);
-                        return cache;
-                }
-
-                log_warning("Unknown interface naming scheme '%s' requested, ignoring.", k);
-        }
-
-        cache = naming_scheme_from_name(DEFAULT_NET_NAMING_SCHEME);
-        assert(cache);
-        log_info("Using default interface naming scheme '%s'.", cache->name);
-
-        return cache;
-}
-
-static bool naming_scheme_has(NamingSchemeFlags flags) {
-        return FLAGS_SET(naming_scheme()->flags, flags);
-}
-
 /* skip intermediate virtio devices */
 static sd_device *skip_virtio(sd_device *dev) {
         sd_device *parent;
index 3a61be10caa32fe1731a2069b81f33eba5cff9ea..48ce295a46513fcc250e3ca29ec12775d965b6c7 100644 (file)
@@ -139,7 +139,7 @@ int udev_builtin_add_property(sd_device *dev, bool test, const char *key, const
                                               key, val ? "=" : "", strempty(val));
 
         if (test)
-                printf("%s=%s\n", key, val);
+                printf("%s=%s\n", key, strempty(val));
 
         return 0;
 }
diff --git a/test/test-network/conf/25-route-ipv6-src.network b/test/test-network/conf/25-route-ipv6-src.network
new file mode 100644 (file)
index 0000000..4e551c0
--- /dev/null
@@ -0,0 +1,16 @@
+# This test cannot use a dummy interface: IPv6 addresses
+# are added without having to go through tentative state
+
+[Match]
+Name=bond199
+
+[Network]
+LinkLocalAddressing=ipv6
+Address=2001:1234:56:8f63::1/64
+Address=2001:1234:56:8f63::2/64
+IPv6AcceptRA=no
+
+[Route]
+Destination=abcd::/16
+Gateway=2001:1234:56:8f63::1:1
+PreferredSource=2001:1234:56:8f63::2
index 5f57631cfb7d952709bf7b84fadefc1c26acf8d9..33ec40b012997bdafe8f4125fa2cdf6fee486653 100755 (executable)
@@ -551,6 +551,7 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         '25-link-section-unmanaged.network',
         '25-route-gateway.network',
         '25-route-gateway-on-link.network',
+        '25-route-ipv6-src.network',
         '25-route-reverse-order.network',
         '25-route-section.network',
         '25-route-tcp-window-settings.network',
@@ -784,6 +785,22 @@ class NetworkdNetWorkTests(unittest.TestCase, Utilities):
         self.assertRegex(output, 'scope')
         self.assertRegex(output, 'link')
 
+    def test_ip_route_ipv6_src_route(self):
+        # a dummy device does not make the addresses go through tentative state, so we
+        # reuse a bond from an earlier test, which does make the addresses go through
+        # tentative state, and do our test on that
+        self.copy_unit_to_networkd_unit_path('23-active-slave.network', '25-route-ipv6-src.network', '25-bond-active-backup-slave.netdev', '12-dummy.netdev')
+        self.start_networkd()
+
+        self.assertTrue(self.link_exits('dummy98'))
+        self.assertTrue(self.link_exits('bond199'))
+
+        output = subprocess.check_output(['ip', '-6', 'route', 'list', 'dev', 'bond199']).rstrip().decode('utf-8')
+        print(output)
+        self.assertRegex(output, 'abcd::/16')
+        self.assertRegex(output, 'src')
+        self.assertRegex(output, '2001:1234:56:8f63::2')
+
     def test_ip_link_mac_address(self):
         self.copy_unit_to_networkd_unit_path('25-address-link-section.network', '12-dummy.netdev')
         self.start_networkd()
index 43087980a94a3125f183ce5bc44f2d822777b321..3b3003835cebe3877ff0181cc2573441045c537f 100755 (executable)
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/bin/sh
 
 set -e