mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-01-11 05:17:44 +03:00
nspawn: Generate unique short veth names
This commit lowers the chance of having veth name conflicts for machines created with similar names. Replaces: #12865 Fixes: #13417
This commit is contained in:
parent
b355d0c9af
commit
bc5ea049f2
@ -835,7 +835,11 @@
|
|||||||
container names may have a length up to 64 characters. As this option derives the host-side interface
|
container names may have a length up to 64 characters. As this option derives the host-side interface
|
||||||
name from the container name the name is possibly truncated. Thus, care needs to be taken to ensure
|
name from the container name the name is possibly truncated. Thus, care needs to be taken to ensure
|
||||||
that interface names remain unique in this case, or even better container names are generally not
|
that interface names remain unique in this case, or even better container names are generally not
|
||||||
chosen longer than 12 characters, to avoid the truncation. Alternatively, the
|
chosen longer than 12 characters, to avoid the truncation. If the name is truncated,
|
||||||
|
<command>systemd-nspawn</command> will automatically append a 4-digit hash value to the name to
|
||||||
|
reduce the chance of collisions. However, the hash algorithm is not collision-free. (See
|
||||||
|
<citerefentry><refentrytitle>systemd.net-naming-scheme</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||||
|
for details on older naming algorithms for this interface). Alternatively, the
|
||||||
<option>--network-veth-extra=</option> option may be used, which allows free configuration of the
|
<option>--network-veth-extra=</option> option may be used, which allows free configuration of the
|
||||||
host-side interface name independently of the container name — but might require a bit more
|
host-side interface name independently of the container name — but might require a bit more
|
||||||
additional configuration in case bridging in a fashion similar to <option>--network-bridge=</option>
|
additional configuration in case bridging in a fashion similar to <option>--network-bridge=</option>
|
||||||
|
@ -46,6 +46,11 @@
|
|||||||
devices based on those properties. See the description of <varname>NamePolicy=</varname> and
|
devices based on those properties. See the description of <varname>NamePolicy=</varname> and
|
||||||
<varname>MACAddressPolicy=</varname> in
|
<varname>MACAddressPolicy=</varname> in
|
||||||
<citerefentry><refentrytitle>systemd.link</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
<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>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -329,7 +334,21 @@
|
|||||||
<para>Previously two-letter interface type prefix was prepended to
|
<para>Previously two-letter interface type prefix was prepended to
|
||||||
<varname>ID_NET_LABEL_ONBOARD=</varname>. This is not done anymore.</para></listitem>
|
<varname>ID_NET_LABEL_ONBOARD=</varname>. This is not done anymore.</para></listitem>
|
||||||
</varlistentry>
|
</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
|
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
|
||||||
particular version of systemd.</para>
|
particular version of systemd.</para>
|
||||||
@ -428,7 +447,8 @@ ID_NET_NAME_PATH=encf5f0</programlisting>
|
|||||||
<para>
|
<para>
|
||||||
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
<citerefentry><refentrytitle>udev</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
|
||||||
<citerefentry><refentrytitle>udevadm</refentrytitle><manvolnum>8</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>
|
</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@
|
|||||||
#include "ether-addr-util.h"
|
#include "ether-addr-util.h"
|
||||||
#include "lockfile-util.h"
|
#include "lockfile-util.h"
|
||||||
#include "missing_network.h"
|
#include "missing_network.h"
|
||||||
|
#include "netif-naming-scheme.h"
|
||||||
#include "netlink-util.h"
|
#include "netlink-util.h"
|
||||||
#include "nspawn-network.h"
|
#include "nspawn-network.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
@ -27,6 +28,7 @@
|
|||||||
#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_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 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 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) {
|
static int remove_one_link(sd_netlink *rtnl, const char *name) {
|
||||||
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
|
||||||
@ -169,6 +171,48 @@ static int add_veth(
|
|||||||
return 0;
|
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,
|
int setup_veth(const char *machine_name,
|
||||||
pid_t pid,
|
pid_t pid,
|
||||||
char iface_name[IFNAMSIZ],
|
char iface_name[IFNAMSIZ],
|
||||||
@ -176,7 +220,9 @@ int setup_veth(const char *machine_name,
|
|||||||
|
|
||||||
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
|
||||||
struct ether_addr mac_host, mac_container;
|
struct ether_addr mac_host, mac_container;
|
||||||
int r, i;
|
unsigned u;
|
||||||
|
char *n;
|
||||||
|
int r;
|
||||||
|
|
||||||
assert(machine_name);
|
assert(machine_name);
|
||||||
assert(pid > 0);
|
assert(pid > 0);
|
||||||
@ -184,8 +230,8 @@ int setup_veth(const char *machine_name,
|
|||||||
|
|
||||||
/* Use two different interface name prefixes depending whether
|
/* Use two different interface name prefixes depending whether
|
||||||
* we are in bridge mode or not. */
|
* we are in bridge mode or not. */
|
||||||
snprintf(iface_name, IFNAMSIZ - 1, "%s-%s",
|
n = strjoina(bridge ? "vb-" : "ve-", machine_name);
|
||||||
bridge ? "vb" : "ve", machine_name);
|
shorten_ifname(n);
|
||||||
|
|
||||||
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
|
r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -199,15 +245,16 @@ int setup_veth(const char *machine_name,
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to connect to netlink: %m");
|
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)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
|
|
||||||
r = parse_ifindex_or_ifname(iface_name, &i);
|
u = if_nametoindex(n);
|
||||||
if (r < 0)
|
if (u == 0)
|
||||||
return log_error_errno(r, "Failed to resolve interface %s: %m", iface_name);
|
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(
|
int setup_veth_extra(
|
||||||
@ -503,7 +550,7 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
|
|||||||
if (!n)
|
if (!n)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
strshorten(n, IFNAMSIZ-1);
|
shorten_ifname(n);
|
||||||
|
|
||||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
@ -578,7 +625,7 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
|
|||||||
if (!n)
|
if (!n)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
strshorten(n, IFNAMSIZ-1);
|
shorten_ifname(n);
|
||||||
|
|
||||||
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
r = sd_netlink_message_append_string(m, IFLA_IFNAME, n);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
@ -11,6 +11,7 @@ static const NamingScheme naming_schemes[] = {
|
|||||||
{ "v240", NAMING_V240 },
|
{ "v240", NAMING_V240 },
|
||||||
{ "v241", NAMING_V241 },
|
{ "v241", NAMING_V241 },
|
||||||
{ "v243", NAMING_V243 },
|
{ "v243", NAMING_V243 },
|
||||||
|
{ "v245", NAMING_V245 },
|
||||||
/* … add more schemes here, as the logic to name devices is updated … */
|
/* … add more schemes here, as the logic to name devices is updated … */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -30,6 +30,7 @@ typedef enum NamingSchemeFlags {
|
|||||||
NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
|
NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
|
||||||
NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
|
NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
|
||||||
NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
|
NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
|
||||||
|
NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
|
||||||
|
|
||||||
/* And now the masks that combine the features above */
|
/* And now the masks that combine the features above */
|
||||||
NAMING_V238 = 0,
|
NAMING_V238 = 0,
|
||||||
@ -37,6 +38,7 @@ typedef enum NamingSchemeFlags {
|
|||||||
NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES,
|
NAMING_V240 = NAMING_V239 | NAMING_INFINIBAND | NAMING_ZERO_ACPI_INDEX | NAMING_ALLOW_RERENAMES,
|
||||||
NAMING_V241 = NAMING_V240 | NAMING_STABLE_VIRTUAL_MACS,
|
NAMING_V241 = NAMING_V240 | NAMING_STABLE_VIRTUAL_MACS,
|
||||||
NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
|
NAMING_V243 = NAMING_V241 | NAMING_NETDEVSIM | NAMING_LABEL_NOPREFIX,
|
||||||
|
NAMING_V245 = NAMING_V243 | NAMING_NSPAWN_LONG_HASH,
|
||||||
|
|
||||||
_NAMING_SCHEME_FLAGS_INVALID = -1,
|
_NAMING_SCHEME_FLAGS_INVALID = -1,
|
||||||
} NamingSchemeFlags;
|
} NamingSchemeFlags;
|
||||||
|
Loading…
Reference in New Issue
Block a user