devices based on those properties. See the description of <varname>NamePolicy=</varname> and
<varname>MACAddressPolicy=</varname> in
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+ <para>Note that while the concept of network interface naming schemes is primarily relevant in the
+ context of <filename>systemd-udevd.service</filename>, the
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ container manager also takes it into account when naming network interfaces, see below.</para>
</refsect1>
<refsect1>
<para>Previously two-letter interface type prefix was prepended to
<varname>ID_NET_LABEL_ONBOARD=</varname>. This is not done anymore.</para></listitem>
</varlistentry>
- </variablelist>
+
+ <varlistentry>
+ <term><constant>v245</constant></term>
+
+ <listitem><para>When
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
+ derives the name for the host side of the network interface created with
+ <option>--network-veth</option> from the container name it previously simply truncated the result
+ at 15 characters if longer (since that's the maximum length for network interface names). From now
+ on, for any interface name that would be longer than 15 characters the last 4 characters are set to
+ a 24bit hash value of the full interface name. This way network interface name collisions between
+ multiple similarly named containers (who only differ in container name suffix) should be less
+ likely (but still possible, since the 24bit hash value is very small).</para></listitem>
+ </varlistentry>
+ </variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
particular version of systemd.</para>
<para>
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
<citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <ulink url="https://systemd.io/PREDICTABLE_INTERFACE_NAMES">Predictable Network Interface Names</ulink>
+ <ulink url="https://systemd.io/PREDICTABLE_INTERFACE_NAMES">Predictable Network Interface Names</ulink>,
+ <citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
</para>
</refsect1>
#include "ether-addr-util.h"
#include "lockfile-util.h"
#include "missing_network.h"
+#include "netif-naming-scheme.h"
#include "netlink-util.h"
#include "nspawn-network.h"
#include "parse-util.h"
#define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
#define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
+#define SHORTEN_IFNAME_HASH_KEY SD_ID128_MAKE(e1,90,a4,04,a8,ef,4b,51,8c,cc,c3,3a,9f,11,fc,a2)
static int remove_one_link(sd_netlink *rtnl, const char *name) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
return 0;
}
+/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet, since we
+ * don't want "/" appear in interface names (since interfaces appear in sysfs as filenames). See section #5
+ * of RFC 4648. */
+static char urlsafe_base64char(int x) {
+ static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789-_";
+ return table[x & 63];
+}
+
+static void shorten_ifname(char *ifname) {
+ char new_ifname[IFNAMSIZ];
+
+ assert(ifname);
+
+ if (strlen(ifname) < IFNAMSIZ) /* Name is short enough */
+ return;
+
+ if (naming_scheme_has(NAMING_NSPAWN_LONG_HASH)) {
+ uint64_t h;
+
+ /* Calculate 64bit hash value */
+ h = siphash24(ifname, strlen(ifname), SHORTEN_IFNAME_HASH_KEY.bytes);
+
+ /* Set the final four bytes (i.e. 32bit) to the lower 24bit of the hash, encoded in url-safe base64 */
+ memcpy(new_ifname, ifname, IFNAMSIZ - 5);
+ new_ifname[IFNAMSIZ - 5] = urlsafe_base64char(h >> 18);
+ new_ifname[IFNAMSIZ - 4] = urlsafe_base64char(h >> 12);
+ new_ifname[IFNAMSIZ - 3] = urlsafe_base64char(h >> 6);
+ new_ifname[IFNAMSIZ - 2] = urlsafe_base64char(h);
+ } else
+ /* On old nspawn versions we just truncated the name, provide compatibility */
+ memcpy(new_ifname, ifname, IFNAMSIZ-1);
+
+ new_ifname[IFNAMSIZ - 1] = 0;
+
+ /* Log the incident to make it more discoverable */
+ log_warning("Network interface name '%s' has been changed to '%s' to fit length constraints.", ifname, new_ifname);
+
+ strcpy(ifname, new_ifname);
+}
+
int setup_veth(const char *machine_name,
pid_t pid,
char iface_name[IFNAMSIZ],
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
struct ether_addr mac_host, mac_container;
- int r, i;
+ unsigned u;
+ char *n;
+ int r;
assert(machine_name);
assert(pid > 0);
/* Use two different interface name prefixes depending whether
* we are in bridge mode or not. */
- snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
- bridge ? "vb" : "ve", machine_name);
+ n = strjoina(bridge ? "vb-" : "ve-", machine_name);
+ shorten_ifname(n);
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
if (r < 0)
if (r < 0)
return log_error_errno(r, "Failed to connect to netlink: %m");
- r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
+ r = add_veth(rtnl, pid, n, &mac_host, "host0", &mac_container);
if (r < 0)
return r;
- r = parse_ifindex_or_ifname(iface_name, &i);
- if (r < 0)
- return log_error_errno(r, "Failed to resolve interface %s: %m", iface_name);
+ u = if_nametoindex(n);
+ if (u == 0)
+ return log_error_errno(errno, "Failed to resolve interface %s: %m", n);
- return i;
+ strcpy(iface_name, n);
+ return (int) u;
}
int setup_veth_extra(
if (!n)
return log_oom();
- strshorten(n, IFNAMSIZ-1);
+ shorten_ifname(n);
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
if (r < 0)
if (!n)
return log_oom();
- strshorten(n, IFNAMSIZ-1);
+ shorten_ifname(n);
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
if (r < 0)