nspawn: container network interface naming

systemd-nspawn now optionally supports colon-separated pair of
host interface name and container interface name for --network-macvlan, --network-ipvlan and --network-interface options.
Also supported in .nspawn configuration files (i.e Interface=, MACVLAN=, IPVLAN= parameters).

man page changed for ntwk interface naming
This commit is contained in:
Thierry Martin 2022-09-05 15:02:06 +02:00 committed by Zbigniew Jędrzejewski-Szmek
parent 3af48a86d9
commit 2f091b1b49
8 changed files with 221 additions and 79 deletions

View file

@ -852,11 +852,13 @@
<varlistentry> <varlistentry>
<term><option>--network-interface=</option></term> <term><option>--network-interface=</option></term>
<listitem><para>Assign the specified network interface to the container. This will remove the <listitem><para>Assign the specified network interface to the container. Either takes a single
specified interface from the calling namespace and place it in the container. When the container interface name, referencing the name on the host, or a colon-separated pair of interfaces, in which
terminates, it is moved back to the calling namespace. Note that case the first one references the name on the host, and the second one the name in the container.
<option>--network-interface=</option> implies <option>--private-network</option>. This option may be When the container terminates, the interface is moved back to the calling namespace and renamed to
used more than once to add multiple network interfaces to the container.</para> its original name. Note that <option>--network-interface=</option> implies
<option>--private-network</option>. This option may be used more than once to add multiple network
interfaces to the container.</para>
<para>Note that any network interface specified this way must already exist at the time the container <para>Note that any network interface specified this way must already exist at the time the container
is started. If the container shall be started automatically at boot via a is started. If the container shall be started automatically at boot via a
@ -880,9 +882,12 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
<term><option>--network-macvlan=</option></term> <term><option>--network-macvlan=</option></term>
<listitem><para>Create a <literal>macvlan</literal> interface of the specified Ethernet network <listitem><para>Create a <literal>macvlan</literal> interface of the specified Ethernet network
interface and add it to the container. A <literal>macvlan</literal> interface is a virtual interface interface and add it to the container. Either takes a single interface name, referencing the name
that adds a second MAC address to an existing physical Ethernet link. The interface in the container on the host, or a colon-separated pair of interfaces, in which case the first one references the name
will be named after the interface on the host, prefixed with <literal>mv-</literal>. Note that on the host, and the second one the name in the container. A <literal>macvlan</literal> interface is
a virtual interface that adds a second MAC address to an existing physical Ethernet link. If the
container interface name is not defined, the interface in the container will be named after the
interface on the host, prefixed with <literal>mv-</literal>. Note that
<option>--network-macvlan=</option> implies <option>--private-network</option>. This option may be <option>--network-macvlan=</option> implies <option>--private-network</option>. This option may be
used more than once to add multiple network interfaces to the container.</para> used more than once to add multiple network interfaces to the container.</para>
@ -895,9 +900,13 @@ After=sys-subsystem-net-devices-ens1.device</programlisting>
<term><option>--network-ipvlan=</option></term> <term><option>--network-ipvlan=</option></term>
<listitem><para>Create an <literal>ipvlan</literal> interface of the specified Ethernet network <listitem><para>Create an <literal>ipvlan</literal> interface of the specified Ethernet network
interface and add it to the container. An <literal>ipvlan</literal> interface is a virtual interface, interface and add it to the container. Either takes a single interface name, referencing the name on
the host, or a colon-separated pair of interfaces, in which case the first one references the name
on the host, and the second one the name in the container. An <literal>ipvlan</literal> interface is
a virtual interface,
similar to a <literal>macvlan</literal> interface, which uses the same MAC address as the underlying similar to a <literal>macvlan</literal> interface, which uses the same MAC address as the underlying
interface. The interface in the container will be named after the interface on the host, prefixed interface. If the container interface name is not defined, the interface in the container will be
named after the interface on the host, prefixed
with <literal>iv-</literal>. Note that <option>--network-ipvlan=</option> implies with <literal>iv-</literal>. Note that <option>--network-ipvlan=</option> implies
<option>--private-network</option>. This option may be used more than once to add multiple network <option>--private-network</option>. This option may be used more than once to add multiple network
interfaces to the container.</para> interfaces to the container.</para>

View file

@ -531,8 +531,11 @@
<varlistentry> <varlistentry>
<term><varname>Interface=</varname></term> <term><varname>Interface=</varname></term>
<listitem><para>Takes a space-separated list of interfaces to <listitem><para>Takes a space-separated list of interfaces to add to the container.
add to the container. This option corresponds to the The interface object is defined either by a single interface name, referencing the name on the host,
or a colon-separated pair of interfaces, in which case the first one references the name on the host,
and the second one the name in the container.
This option corresponds to the
<option>--network-interface=</option> command line switch and <option>--network-interface=</option> command line switch and
implies <varname>Private=yes</varname>. This option is implies <varname>Private=yes</varname>. This option is
privileged (see above).</para></listitem> privileged (see above).</para></listitem>
@ -544,7 +547,9 @@
<listitem><para>Takes a space-separated list of interfaces to <listitem><para>Takes a space-separated list of interfaces to
add MACLVAN or IPVLAN interfaces to, which are then added to add MACLVAN or IPVLAN interfaces to, which are then added to
the container. These options correspond to the the container. The interface object is defined either by a single interface name, referencing the name
on the host, or a colon-separated pair of interfaces, in which case the first one references the name
on the host, and the second one the name in the container. These options correspond to the
<option>--network-macvlan=</option> and <option>--network-macvlan=</option> and
<option>--network-ipvlan=</option> command line switches and <option>--network-ipvlan=</option> command line switches and
imply <varname>Private=yes</varname>. These options are imply <varname>Private=yes</varname>. These options are

View file

@ -72,9 +72,9 @@ Files.PrivateUsersChown, config_parse_userns_chown, 0,
Files.PrivateUsersOwnership, config_parse_userns_ownership, 0, offsetof(Settings, userns_ownership) Files.PrivateUsersOwnership, config_parse_userns_ownership, 0, offsetof(Settings, userns_ownership)
Files.BindUser, config_parse_bind_user, 0, offsetof(Settings, bind_user) Files.BindUser, config_parse_bind_user, 0, offsetof(Settings, bind_user)
Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network) Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network)
Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces) Network.Interface, config_parse_network_iface_pair, 0, offsetof(Settings, network_interfaces)
Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan) Network.MACVLAN, config_parse_macvlan_iface_pair, 0, offsetof(Settings, network_macvlan)
Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan) Network.IPVLAN, config_parse_ipvlan_iface_pair, 0, offsetof(Settings, network_ipvlan)
Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth)
Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0 Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0
Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge) Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge)

View file

@ -463,7 +463,7 @@ int remove_bridge(const char *bridge_name) {
return remove_one_link(rtnl, bridge_name); return remove_one_link(rtnl, bridge_name);
} }
int test_network_interface_initialized(const char *name) { static int test_network_interface_initialized(const char *name) {
_cleanup_(sd_device_unrefp) sd_device *d = NULL; _cleanup_(sd_device_unrefp) sd_device *d = NULL;
int r; int r;
@ -491,18 +491,28 @@ int test_network_interface_initialized(const char *name) {
return 0; return 0;
} }
int move_network_interfaces(int netns_fd, char **ifaces) { int test_network_interfaces_initialized(char **iface_pairs) {
int r;
STRV_FOREACH_PAIR(a, b, iface_pairs) {
r = test_network_interface_initialized(*a);
if (r < 0)
return r;
}
return 0;
}
int move_network_interfaces(int netns_fd, char **iface_pairs) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r; int r;
if (strv_isempty(ifaces)) if (strv_isempty(iface_pairs))
return 0; return 0;
r = sd_netlink_open(&rtnl); r = sd_netlink_open(&rtnl);
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");
STRV_FOREACH(i, ifaces) { STRV_FOREACH_PAIR(i, b, iface_pairs) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int ifi; int ifi;
@ -518,6 +528,12 @@ int move_network_interfaces(int netns_fd, char **ifaces) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to append namespace fd to netlink message: %m"); return log_error_errno(r, "Failed to append namespace fd to netlink message: %m");
if (!streq(*b, *i)) {
r = sd_netlink_message_append_string(m, IFLA_IFNAME, *b);
if (r < 0)
return log_error_errno(r, "Failed to add netlink interface name: %m");
}
r = sd_netlink_call(rtnl, m, 0, NULL); r = sd_netlink_call(rtnl, m, 0, NULL);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i); return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i);
@ -526,23 +542,23 @@ int move_network_interfaces(int netns_fd, char **ifaces) {
return 0; return 0;
} }
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
unsigned idx = 0; unsigned idx = 0;
int r; int r;
if (strv_isempty(ifaces)) if (strv_isempty(iface_pairs))
return 0; return 0;
r = sd_netlink_open(&rtnl); r = sd_netlink_open(&rtnl);
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");
STRV_FOREACH(i, ifaces) { STRV_FOREACH_PAIR(i, b, iface_pairs) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
_cleanup_free_ char *n = NULL, *a = NULL; _cleanup_free_ char *n = NULL;
int shortened, ifi;
struct ether_addr mac; struct ether_addr mac;
int ifi;
ifi = rtnl_resolve_interface_or_warn(&rtnl, *i); ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
if (ifi < 0) if (ifi < 0)
@ -560,16 +576,11 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add netlink interface index: %m"); return log_error_errno(r, "Failed to add netlink interface index: %m");
n = strjoin("mv-", *i); n = strdup(*b);
if (!n) if (!n)
return log_oom(); return log_oom();
r = shorten_ifname(n); shortened = shorten_ifname(n);
if (r > 0) {
a = strjoin("mv-", *i);
if (!a)
return log_oom();
}
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)
@ -607,27 +618,28 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add new macvlan interfaces: %m"); return log_error_errno(r, "Failed to add new macvlan interfaces: %m");
(void) set_alternative_ifname(rtnl, n, a); if (shortened > 0)
(void) set_alternative_ifname(rtnl, n, *b);
} }
return 0; return 0;
} }
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs) {
_cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL;
int r; int r;
if (strv_isempty(ifaces)) if (strv_isempty(iface_pairs))
return 0; return 0;
r = sd_netlink_open(&rtnl); r = sd_netlink_open(&rtnl);
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");
STRV_FOREACH(i, ifaces) { STRV_FOREACH_PAIR(i, b, iface_pairs) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
_cleanup_free_ char *n = NULL, *a = NULL; _cleanup_free_ char *n = NULL;
int ifi; int shortened, ifi ;
ifi = rtnl_resolve_interface_or_warn(&rtnl, *i); ifi = rtnl_resolve_interface_or_warn(&rtnl, *i);
if (ifi < 0) if (ifi < 0)
@ -641,16 +653,11 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add netlink interface index: %m"); return log_error_errno(r, "Failed to add netlink interface index: %m");
n = strjoin("iv-", *i); n = strdup(*b);
if (!n) if (!n)
return log_oom(); return log_oom();
r = shorten_ifname(n); shortened = shorten_ifname(n);
if (r > 0) {
a = strjoin("iv-", *i);
if (!a)
return log_oom();
}
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)
@ -684,7 +691,8 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) {
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to add new ipvlan interfaces: %m"); return log_error_errno(r, "Failed to add new ipvlan interfaces: %m");
(void) set_alternative_ifname(rtnl, n, a); if (shortened > 0)
(void) set_alternative_ifname(rtnl, n, *b);
} }
return 0; return 0;
@ -742,3 +750,51 @@ int remove_veth_links(const char *primary, char **pairs) {
return 0; return 0;
} }
static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) {
_cleanup_free_ char *a = NULL, *b = NULL;
int r;
r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
if (r < 0)
return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype);
if (r == 0)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Short read while reading %s parameter: %m", iftype);
if (!ifname_valid(a))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s, interface name not valid: %s", iftype, a);
if (isempty(p)) {
if (ifprefix)
b = strjoin(ifprefix, a);
else
b = strdup(a);
} else
b = strdup(p);
if (!b)
return log_oom();
if (!ifname_valid(b))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"%s, interface name not valid: %s", iftype, b);
r = strv_push_pair(l, a, b);
if (r < 0)
return log_oom();
a = b = NULL;
return 0;
}
int interface_pair_parse(char ***l, const char *p) {
return network_iface_pair_parse("Network interface", l, p, NULL);
}
int macvlan_pair_parse(char ***l, const char *p) {
return network_iface_pair_parse("MACVLAN network interface", l, p, "mv-");
}
int ipvlan_pair_parse(char ***l, const char *p) {
return network_iface_pair_parse("IPVLAN network interface", l, p, "iv-");
}

View file

@ -5,7 +5,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <sys/types.h> #include <sys/types.h>
int test_network_interface_initialized(const char *name); int test_network_interfaces_initialized(char **iface_pairs);
int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge); int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge);
int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
@ -13,11 +13,15 @@ int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs);
int setup_bridge(const char *veth_name, const char *bridge_name, bool create); int setup_bridge(const char *veth_name, const char *bridge_name, bool create);
int remove_bridge(const char *bridge_name); int remove_bridge(const char *bridge_name);
int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces); int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs);
int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs);
int move_network_interfaces(int netns_fd, char **ifaces); int move_network_interfaces(int netns_fd, char **iface_pairs);
int veth_extra_parse(char ***l, const char *p); int veth_extra_parse(char ***l, const char *p);
int remove_veth_links(const char *primary, char **pairs); int remove_veth_links(const char *primary, char **pairs);
int interface_pair_parse(char ***l, const char *p);
int macvlan_pair_parse(char ***l, const char *p);
int ipvlan_pair_parse(char ***l, const char *p);

View file

@ -469,6 +469,69 @@ int config_parse_veth_extra(
return 0; return 0;
} }
int config_parse_network_iface_pair(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char*** l = data;
assert(filename);
assert(lvalue);
assert(rvalue);
return interface_pair_parse(l, rvalue);
}
int config_parse_macvlan_iface_pair(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char*** l = data;
assert(filename);
assert(lvalue);
assert(rvalue);
return macvlan_pair_parse(l, rvalue);
}
int config_parse_ipvlan_iface_pair(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char*** l = data;
assert(filename);
assert(lvalue);
assert(rvalue);
return ipvlan_pair_parse(l, rvalue);
}
int config_parse_network_zone( int config_parse_network_zone(
const char *unit, const char *unit,
const char *filename, const char *filename,

View file

@ -259,6 +259,9 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs);
CONFIG_PARSER_PROTOTYPE(config_parse_overlay); CONFIG_PARSER_PROTOTYPE(config_parse_overlay);
CONFIG_PARSER_PROTOTYPE(config_parse_inaccessible); CONFIG_PARSER_PROTOTYPE(config_parse_inaccessible);
CONFIG_PARSER_PROTOTYPE(config_parse_veth_extra); CONFIG_PARSER_PROTOTYPE(config_parse_veth_extra);
CONFIG_PARSER_PROTOTYPE(config_parse_network_iface_pair);
CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_iface_pair);
CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_iface_pair);
CONFIG_PARSER_PROTOTYPE(config_parse_network_zone); CONFIG_PARSER_PROTOTYPE(config_parse_network_zone);
CONFIG_PARSER_PROTOTYPE(config_parse_boot); CONFIG_PARSER_PROTOTYPE(config_parse_boot);
CONFIG_PARSER_PROTOTYPE(config_parse_pid2); CONFIG_PARSER_PROTOTYPE(config_parse_pid2);

View file

@ -377,13 +377,13 @@ static int help(void) {
" --private-users-ownership=auto\n\n" " --private-users-ownership=auto\n\n"
"%3$sNetworking:%4$s\n" "%3$sNetworking:%4$s\n"
" --private-network Disable network in container\n" " --private-network Disable network in container\n"
" --network-interface=INTERFACE\n" " --network-interface=HOSTIF[:CONTAINERIF]\n"
" Assign an existing network interface to the\n" " Assign an existing network interface to the\n"
" container\n" " container\n"
" --network-macvlan=INTERFACE\n" " --network-macvlan=HOSTIF[:CONTAINERIF]\n"
" Create a macvlan network interface based on an\n" " Create a macvlan network interface based on an\n"
" existing network interface to the container\n" " existing network interface to the container\n"
" --network-ipvlan=INTERFACE\n" " --network-ipvlan=HOSTIF[:CONTAINERIF]\n"
" Create an ipvlan network interface based on an\n" " Create an ipvlan network interface based on an\n"
" existing network interface to the container\n" " existing network interface to the container\n"
" -n --network-veth Add a virtual Ethernet connection between host\n" " -n --network-veth Add a virtual Ethernet connection between host\n"
@ -924,51 +924,28 @@ static int parse_argv(int argc, char *argv[]) {
break; break;
case ARG_NETWORK_INTERFACE: case ARG_NETWORK_INTERFACE:
if (!ifname_valid(optarg)) r = interface_pair_parse(&arg_network_interfaces, optarg);
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Network interface name not valid: %s", optarg);
r = test_network_interface_initialized(optarg);
if (r < 0) if (r < 0)
return r; return r;
if (strv_extend(&arg_network_interfaces, optarg) < 0)
return log_oom();
arg_private_network = true; arg_private_network = true;
arg_settings_mask |= SETTING_NETWORK; arg_settings_mask |= SETTING_NETWORK;
break; break;
case ARG_NETWORK_MACVLAN: case ARG_NETWORK_MACVLAN:
r = macvlan_pair_parse(&arg_network_macvlan, optarg);
if (!ifname_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"MACVLAN network interface name not valid: %s", optarg);
r = test_network_interface_initialized(optarg);
if (r < 0) if (r < 0)
return r; return r;
if (strv_extend(&arg_network_macvlan, optarg) < 0)
return log_oom();
arg_private_network = true; arg_private_network = true;
arg_settings_mask |= SETTING_NETWORK; arg_settings_mask |= SETTING_NETWORK;
break; break;
case ARG_NETWORK_IPVLAN: case ARG_NETWORK_IPVLAN:
r = ipvlan_pair_parse(&arg_network_ipvlan, optarg);
if (!ifname_valid(optarg))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"IPVLAN network interface name not valid: %s", optarg);
r = test_network_interface_initialized(optarg);
if (r < 0) if (r < 0)
return r; return r;
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
return log_oom();
_fallthrough_; _fallthrough_;
case ARG_PRIVATE_NETWORK: case ARG_PRIVATE_NETWORK:
arg_private_network = true; arg_private_network = true;
@ -1894,6 +1871,23 @@ static int verify_arguments(void) {
return 0; return 0;
} }
static int verify_network_interfaces_initialized(void) {
int r;
r = test_network_interfaces_initialized(arg_network_interfaces);
if (r < 0)
return r;
r = test_network_interfaces_initialized(arg_network_macvlan);
if (r < 0)
return r;
r = test_network_interfaces_initialized(arg_network_ipvlan);
if (r < 0)
return r;
return 0;
}
int userns_lchown(const char *p, uid_t uid, gid_t gid) { int userns_lchown(const char *p, uid_t uid, gid_t gid) {
assert(p); assert(p);
@ -5288,6 +5282,10 @@ static int run_container(
_exit(EXIT_FAILURE); _exit(EXIT_FAILURE);
} }
/* Reverse network interfaces pair list so that interfaces get their initial name back.
* This is about ensuring interfaces get their old name back when being moved back. */
arg_network_interfaces = strv_reverse(arg_network_interfaces);
r = move_network_interfaces(parent_netns_fd, arg_network_interfaces); r = move_network_interfaces(parent_netns_fd, arg_network_interfaces);
if (r < 0) if (r < 0)
log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m"); log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m");
@ -5506,6 +5504,10 @@ static int run(int argc, char *argv[]) {
if (r < 0) if (r < 0)
goto finish; goto finish;
r = verify_network_interfaces_initialized();
if (r < 0)
goto finish;
/* Reapply environment settings. */ /* Reapply environment settings. */
(void) detect_unified_cgroup_hierarchy_from_environment(); (void) detect_unified_cgroup_hierarchy_from_environment();