summaryrefslogtreecommitdiff
path: root/src/nspawn/nspawn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nspawn/nspawn.c')
-rw-r--r--src/nspawn/nspawn.c89
1 files changed, 85 insertions, 4 deletions
diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c
index 3fc6cc955c..0479389682 100644
--- a/src/nspawn/nspawn.c
+++ b/src/nspawn/nspawn.c
@@ -176,6 +176,7 @@ static char **arg_network_ipvlan = NULL;
static bool arg_network_veth = false;
static char **arg_network_veth_extra = NULL;
static char *arg_network_bridge = NULL;
+static char *arg_network_zone = NULL;
static unsigned long arg_personality = PERSONALITY_INVALID;
static char *arg_image = NULL;
static VolatileMode arg_volatile_mode = VOLATILE_NO;
@@ -234,6 +235,8 @@ static void help(void) {
" Add a virtual Ethernet connection between host\n"
" and container and add it to an existing bridge on\n"
" the host\n"
+ " --network-zone=NAME Add a virtual Ethernet connection to the container,\n"
+ " and add it to an automatically managed bridge interface\n"
" -p --port=[PROTOCOL:]HOSTPORT[:CONTAINERPORT]\n"
" Expose a container IP port on the host\n"
" -Z --selinux-context=SECLABEL\n"
@@ -357,6 +360,7 @@ static int parse_argv(int argc, char *argv[]) {
ARG_NETWORK_MACVLAN,
ARG_NETWORK_IPVLAN,
ARG_NETWORK_BRIDGE,
+ ARG_NETWORK_ZONE,
ARG_NETWORK_VETH_EXTRA,
ARG_PERSONALITY,
ARG_VOLATILE,
@@ -404,6 +408,7 @@ static int parse_argv(int argc, char *argv[]) {
{ "network-veth", no_argument, NULL, 'n' },
{ "network-veth-extra", required_argument, NULL, ARG_NETWORK_VETH_EXTRA},
{ "network-bridge", required_argument, NULL, ARG_NETWORK_BRIDGE },
+ { "network-zone", required_argument, NULL, ARG_NETWORK_ZONE },
{ "personality", required_argument, NULL, ARG_PERSONALITY },
{ "image", required_argument, NULL, 'i' },
{ "volatile", optional_argument, NULL, ARG_VOLATILE },
@@ -466,7 +471,35 @@ static int parse_argv(int argc, char *argv[]) {
arg_settings_mask |= SETTING_USER;
break;
+ case ARG_NETWORK_ZONE: {
+ char *j;
+
+ j = strappend("vz-", optarg);
+ if (!j)
+ return log_oom();
+
+ if (!ifname_valid(j)) {
+ log_error("Network zone name not valid: %s", j);
+ free(j);
+ return -EINVAL;
+ }
+
+ free(arg_network_zone);
+ arg_network_zone = j;
+
+ arg_network_veth = true;
+ arg_private_network = true;
+ arg_settings_mask |= SETTING_NETWORK;
+ break;
+ }
+
case ARG_NETWORK_BRIDGE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Bridge interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
r = free_and_strdup(&arg_network_bridge, optarg);
if (r < 0)
return log_oom();
@@ -489,6 +522,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_INTERFACE:
+
+ if (!ifname_valid(optarg)) {
+ log_error("Network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_interfaces, optarg) < 0)
return log_oom();
@@ -497,6 +536,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_MACVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("MACVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_macvlan, optarg) < 0)
return log_oom();
@@ -505,6 +550,12 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_NETWORK_IPVLAN:
+
+ if (!ifname_valid(optarg)) {
+ log_error("IPVLAN network interface name not valid: %s", optarg);
+ return -EINVAL;
+ }
+
if (strv_extend(&arg_network_ipvlan, optarg) < 0)
return log_oom();
@@ -1003,6 +1054,11 @@ static int parse_argv(int argc, char *argv[]) {
return -EINVAL;
}
+ if (arg_network_bridge && arg_network_zone) {
+ log_error("--network-bridge= and --network-zone= may not be combined.");
+ return -EINVAL;
+ }
+
if (argc > optind) {
arg_parameters = strv_copy(argv + optind);
if (!arg_parameters)
@@ -3271,6 +3327,7 @@ static int load_settings(void) {
(settings->private_network >= 0 ||
settings->network_veth >= 0 ||
settings->network_bridge ||
+ settings->network_zone ||
settings->network_interfaces ||
settings->network_macvlan ||
settings->network_ipvlan ||
@@ -3301,6 +3358,10 @@ static int load_settings(void) {
free(arg_network_bridge);
arg_network_bridge = settings->network_bridge;
settings->network_bridge = NULL;
+
+ free(arg_network_zone);
+ arg_network_zone = settings->network_zone;
+ settings->network_zone = NULL;
}
}
@@ -3346,7 +3407,7 @@ int main(int argc, char *argv[]) {
int ret = EXIT_SUCCESS;
union in_addr_union exposed = {};
_cleanup_release_lock_file_ LockFile tree_global_lock = LOCK_FILE_INIT, tree_local_lock = LOCK_FILE_INIT;
- bool interactive;
+ bool interactive, veth_created = false;
log_parse_environment();
log_open();
@@ -3800,14 +3861,23 @@ int main(int argc, char *argv[]) {
goto finish;
if (arg_network_veth) {
- r = setup_veth(arg_machine, pid, veth_name, !!arg_network_bridge);
+ r = setup_veth(arg_machine, pid, veth_name,
+ arg_network_bridge || arg_network_zone);
if (r < 0)
goto finish;
else if (r > 0)
ifi = r;
if (arg_network_bridge) {
- r = setup_bridge(veth_name, arg_network_bridge);
+ /* Add the interface to a bridge */
+ r = setup_bridge(veth_name, arg_network_bridge, false);
+ if (r < 0)
+ goto finish;
+ if (r > 0)
+ ifi = r;
+ } else if (arg_network_zone) {
+ /* Add the interface to a bridge, possibly creating it */
+ r = setup_bridge(veth_name, arg_network_zone, true);
if (r < 0)
goto finish;
if (r > 0)
@@ -3819,6 +3889,12 @@ int main(int argc, char *argv[]) {
if (r < 0)
goto finish;
+ /* We created the primary and extra veth links now; let's remember this, so that we know to
+ remove them later on. Note that we don't bother with removing veth links that were created
+ here when their setup failed half-way, because in that case the kernel should be able to
+ remove them on its own, since they cannot be referenced by anything yet. */
+ veth_created = true;
+
r = setup_macvlan(arg_machine, pid, arg_network_macvlan);
if (r < 0)
goto finish;
@@ -3981,7 +4057,9 @@ int main(int argc, char *argv[]) {
}
expose_port_flush(arg_expose_ports, &exposed);
+
(void) remove_veth_links(veth_name, arg_network_veth_extra);
+ veth_created = false;
}
finish:
@@ -4014,7 +4092,10 @@ finish:
}
expose_port_flush(arg_expose_ports, &exposed);
- (void) remove_veth_links(veth_name, arg_network_veth_extra);
+
+ if (veth_created)
+ (void) remove_veth_links(veth_name, arg_network_veth_extra);
+ (void) remove_bridge(arg_network_zone);
free(arg_directory);
free(arg_template);