* $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.
* $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.
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>
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
# (at your option) any later version.
[Link]
-NamePolicy=kernel database onboard slot path
+NamePolicy=keep kernel database onboard slot path
MACAddressPolicy=persistent
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 {
#include "network-internal.h"
#include "siphash24.h"
#include "sparse-endian.h"
+#include "stdio-util.h"
#include "virt.h"
#define SYSTEMD_PEN 43793
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)
#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"
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;
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) {
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;
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;
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;
/* 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;
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");
Set *routes_foreign;
bool addresses_configured;
+ bool addresses_ready;
sd_dhcp_client *dhcp_client;
sd_dhcp_lease *dhcp_lease;
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
#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"
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;
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;
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);
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:
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);
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);
typedef enum NamePolicy {
NAMEPOLICY_KERNEL,
+ NAMEPOLICY_KEEP,
NAMEPOLICY_DATABASE,
NAMEPOLICY_ONBOARD,
NAMEPOLICY_SLOT,
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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);
+}
#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,
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;
key, val ? "=" : "", strempty(val));
if (test)
- printf("%s=%s\n", key, val);
+ printf("%s=%s\n", key, strempty(val));
return 0;
}
--- /dev/null
+# 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
'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',
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()
-#!/bin/bash
+#!/bin/sh
set -e