Skip to content

Commit eb253fb

Browse files
authored
Merge pull request systemd#14467 from poettering/nspawn-short-names-rework
nspawn: change how we truncate --network-veth names
2 parents 6bbeef2 + bc5ea04 commit eb253fb

File tree

9 files changed

+93
-18
lines changed

9 files changed

+93
-18
lines changed

man/systemd-nspawn.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,11 @@
835835
container names may have a length up to 64 characters. As this option derives the host-side interface
836836
name from the container name the name is possibly truncated. Thus, care needs to be taken to ensure
837837
that interface names remain unique in this case, or even better container names are generally not
838-
chosen longer than 12 characters, to avoid the truncation. Alternatively, the
838+
chosen longer than 12 characters, to avoid the truncation. If the name is truncated,
839+
<command>systemd-nspawn</command> will automatically append a 4-digit hash value to the name to
840+
reduce the chance of collisions. However, the hash algorithm is not collision-free. (See
841+
<citerefentry><refentrytitle>systemd.net-naming-scheme</refentrytitle><manvolnum>7</manvolnum></citerefentry>
842+
for details on older naming algorithms for this interface). Alternatively, the
839843
<option>--network-veth-extra=</option> option may be used, which allows free configuration of the
840844
host-side interface name independently of the container name — but might require a bit more
841845
additional configuration in case bridging in a fashion similar to <option>--network-bridge=</option>

man/systemd.net-naming-scheme.xml

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@
4646
devices based on those properties. See the description of <varname>NamePolicy=</varname> and
4747
<varname>MACAddressPolicy=</varname> in
4848
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
49+
50+
<para>Note that while the concept of network interface naming schemes is primarily relevant in the
51+
context of <filename>systemd-udevd.service</filename>, the
52+
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
53+
container manager also takes it into account when naming network interfaces, see below.</para>
4954
</refsect1>
5055

5156
<refsect1>
@@ -329,7 +334,21 @@
329334
<para>Previously two-letter interface type prefix was prepended to
330335
<varname>ID_NET_LABEL_ONBOARD=</varname>. This is not done anymore.</para></listitem>
331336
</varlistentry>
332-
</variablelist>
337+
338+
<varlistentry>
339+
<term><constant>v245</constant></term>
340+
341+
<listitem><para>When
342+
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
343+
derives the name for the host side of the network interface created with
344+
<option>--network-veth</option> from the container name it previously simply truncated the result
345+
at 15 characters if longer (since that's the maximum length for network interface names). From now
346+
on, for any interface name that would be longer than 15 characters the last 4 characters are set to
347+
a 24bit hash value of the full interface name. This way network interface name collisions between
348+
multiple similarly named containers (who only differ in container name suffix) should be less
349+
likely (but still possible, since the 24bit hash value is very small).</para></listitem>
350+
</varlistentry>
351+
</variablelist>
333352

334353
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
335354
particular version of systemd.</para>
@@ -428,7 +447,8 @@ ID_NET_NAME_PATH=encf5f0</programlisting>
428447
<para>
429448
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
430449
<citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
431-
<ulink url="https://systemd.io/PREDICTABLE_INTERFACE_NAMES">Predictable Network Interface Names</ulink>
450+
<ulink url="https://systemd.io/PREDICTABLE_INTERFACE_NAMES">Predictable Network Interface Names</ulink>,
451+
<citerefentry><refentrytitle>systemd-nspawn</refentrytitle><manvolnum>1</manvolnum></citerefentry>
432452
</para>
433453
</refsect1>
434454

src/nspawn/nspawn-network.c

Lines changed: 57 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "ether-addr-util.h"
1212
#include "lockfile-util.h"
1313
#include "missing_network.h"
14+
#include "netif-naming-scheme.h"
1415
#include "netlink-util.h"
1516
#include "nspawn-network.h"
1617
#include "parse-util.h"
@@ -27,6 +28,7 @@
2728
#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)
2829
#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)
2930
#define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
31+
#define SHORTEN_IFNAME_HASH_KEY SD_ID128_MAKE(e1,90,a4,04,a8,ef,4b,51,8c,cc,c3,3a,9f,11,fc,a2)
3032

3133
static int remove_one_link(sd_netlink *rtnl, const char *name) {
3234
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
@@ -169,23 +171,67 @@ static int add_veth(
169171
return 0;
170172
}
171173

174+
/* This is almost base64char(), but not entirely, as it uses the "url and filename safe" alphabet, since we
175+
* don't want "/" appear in interface names (since interfaces appear in sysfs as filenames). See section #5
176+
* of RFC 4648. */
177+
static char urlsafe_base64char(int x) {
178+
static const char table[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
179+
"abcdefghijklmnopqrstuvwxyz"
180+
"0123456789-_";
181+
return table[x & 63];
182+
}
183+
184+
static void shorten_ifname(char *ifname) {
185+
char new_ifname[IFNAMSIZ];
186+
187+
assert(ifname);
188+
189+
if (strlen(ifname) < IFNAMSIZ) /* Name is short enough */
190+
return;
191+
192+
if (naming_scheme_has(NAMING_NSPAWN_LONG_HASH)) {
193+
uint64_t h;
194+
195+
/* Calculate 64bit hash value */
196+
h = siphash24(ifname, strlen(ifname), SHORTEN_IFNAME_HASH_KEY.bytes);
197+
198+
/* Set the final four bytes (i.e. 32bit) to the lower 24bit of the hash, encoded in url-safe base64 */
199+
memcpy(new_ifname, ifname, IFNAMSIZ - 5);
200+
new_ifname[IFNAMSIZ - 5] = urlsafe_base64char(h >> 18);
201+
new_ifname[IFNAMSIZ - 4] = urlsafe_base64char(h >> 12);
202+
new_ifname[IFNAMSIZ - 3] = urlsafe_base64char(h >> 6);
203+
new_ifname[IFNAMSIZ - 2] = urlsafe_base64char(h);
204+
} else
205+
/* On old nspawn versions we just truncated the name, provide compatibility */
206+
memcpy(new_ifname, ifname, IFNAMSIZ-1);
207+
208+
new_ifname[IFNAMSIZ - 1] = 0;
209+
210+
/* Log the incident to make it more discoverable */
211+
log_warning("Network interface name '%s' has been changed to '%s' to fit length constraints.", ifname, new_ifname);
212+
213+
strcpy(ifname, new_ifname);
214+
}
215+
172216
int setup_veth(const char *machine_name,
173217
pid_t pid,
174218
char iface_name[IFNAMSIZ],
175219
bool bridge) {
176220

177221
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
178222
struct ether_addr mac_host, mac_container;
179-
int r, i;
223+
unsigned u;
224+
char *n;
225+
int r;
180226

181227
assert(machine_name);
182228
assert(pid > 0);
183229
assert(iface_name);
184230

185231
/* Use two different interface name prefixes depending whether
186232
* we are in bridge mode or not. */
187-
snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
188-
bridge ? "vb" : "ve", machine_name);
233+
n = strjoina(bridge ? "vb-" : "ve-", machine_name);
234+
shorten_ifname(n);
189235

190236
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
191237
if (r < 0)
@@ -199,15 +245,16 @@ int setup_veth(const char *machine_name,
199245
if (r < 0)
200246
return log_error_errno(r, "Failed to connect to netlink: %m");
201247

202-
r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container);
248+
r = add_veth(rtnl, pid, n, &mac_host, "host0", &mac_container);
203249
if (r < 0)
204250
return r;
205251

206-
r = parse_ifindex_or_ifname(iface_name, &i);
207-
if (r < 0)
208-
return log_error_errno(r, "Failed to resolve interface %s: %m", iface_name);
252+
u = if_nametoindex(n);
253+
if (u == 0)
254+
return log_error_errno(errno, "Failed to resolve interface %s: %m", n);
209255

210-
return i;
256+
strcpy(iface_name, n);
257+
return (int) u;
211258
}
212259

213260
int setup_veth_extra(
@@ -503,7 +550,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
503550
if (!n)
504551
return log_oom();
505552

506-
strshorten(n, IFNAMSIZ-1);
553+
shorten_ifname(n);
507554

508555
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
509556
if (r < 0)
@@ -578,7 +625,7 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
578625
if (!n)
579626
return log_oom();
580627

581-
strshorten(n, IFNAMSIZ-1);
628+
shorten_ifname(n);
582629

583630
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
584631
if (r < 0)

src/shared/meson.build

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,8 @@ shared_sources = files('''
130130
module-util.h
131131
mount-util.c
132132
mount-util.h
133+
netif-naming-scheme.c
134+
netif-naming-scheme.h
133135
nscd-flush.c
134136
nscd-flush.h
135137
nsflags.c
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* SPDX-License-Identifier: LGPL-2.1+ */
2+
23
#include "alloc-util.h"
3-
#include "naming-scheme.h"
4+
#include "netif-naming-scheme.h"
45
#include "proc-cmdline.h"
56
#include "string-util.h"
67

@@ -10,6 +11,7 @@ static const NamingScheme naming_schemes[] = {
1011
{ "v240", NAMING_V240 },
1112
{ "v241", NAMING_V241 },
1213
{ "v243", NAMING_V243 },
14+
{ "v245", NAMING_V245 },
1315
/* … add more schemes here, as the logic to name devices is updated … */
1416
};
1517

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,15 @@ typedef enum NamingSchemeFlags {
3030
NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
3131
NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
3232
NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
33+
NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
3334

3435
/* And now the masks that combine the features above */
3536
NAMING_V238 = 0,
3637
NAMING_V239 = NAMING_V238 | NAMING_SR_IOV_V | NAMING_NPAR_ARI,
3738
NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES,
3839
NAMING_V241 = NAMING_V240 | NAMING_STABLE_VIRTUAL_MACS,
3940
NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
41+
NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH,
4042

4143
_NAMING_SCHEME_FLAGS_INVALID = -1,
4244
} NamingSchemeFlags;

src/udev/meson.build

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ libudev_core_sources = '''
4040
udev-builtin-usb_id.c
4141
net/link-config.c
4242
net/link-config.h
43-
net/naming-scheme.c
44-
net/naming-scheme.h
4543
'''.split()
4644

4745
if conf.get('HAVE_KMOD') == 1

src/udev/net/link-config.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
#include "link-config.h"
1717
#include "log.h"
1818
#include "memory-util.h"
19-
#include "naming-scheme.h"
19+
#include "netif-naming-scheme.h"
2020
#include "netlink-util.h"
2121
#include "network-internal.h"
2222
#include "parse-util.h"

src/udev/udev-builtin-net_id.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
#include "fd-util.h"
2828
#include "fileio.h"
2929
#include "fs-util.h"
30-
#include "naming-scheme.h"
30+
#include "netif-naming-scheme.h"
3131
#include "parse-util.h"
3232
#include "proc-cmdline.h"
3333
#include "stdio-util.h"

0 commit comments

Comments
 (0)