From c188736cd81aab5924073118f11d1b9dc7696382 Mon Sep 17 00:00:00 2001 From: David Gibson Date: Fri, 26 Aug 2022 14:58:38 +1000 Subject: Use explicit --netns option rather than multiplexing with PID When attaching to an existing namespace, pasta can take a PID or the name or path of a network namespace as a non-option parameter. We disambiguate based on what the parameter looks like. Make this more explicit by using a --netns option for explicitly giving the path or name, and treating a non-option argument always as a PID. Signed-off-by: David Gibson [sbrivio: Fix typo in man page] Signed-off-by: Stefano Brivio --- conf.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++------------------- passt.1 | 16 ++++++++++--- 2 files changed, 73 insertions(+), 28 deletions(-) diff --git a/conf.c b/conf.c index fdca582..1d049d6 100644 --- a/conf.c +++ b/conf.c @@ -490,19 +490,51 @@ out: } /** - * conf_ns_opt() - Parse non-option argument to namespace paths + * conf_netns() - Parse --netns option + * @netns: buffer of size PATH_MAX, updated with netns path + * @arg: --netns argument + * + * Return: 0 on success, negative error code otherwise + */ +static int conf_netns(char *netns, const char *arg) +{ + int ret; + + if (!strchr(arg, '/')) { + /* looks like a netns name */ + ret = snprintf(netns, PATH_MAX, "%s/%s", NETNS_RUN_DIR, arg); + } else { + /* otherwise assume it's a netns path */ + ret = snprintf(netns, PATH_MAX, "%s", arg); + } + + if (ret <= 0 || ret > PATH_MAX) { + err("Network namespace name/path %s too long"); + return -E2BIG; + } + + return 0; +} + +/** + * conf_ns_pid() - Parse non-option argument as a PID * @userns: buffer of size PATH_MAX, initially contains --userns * argument (may be empty), updated with userns path - * @netns: buffer of size PATH_MAX, updated with netns path - * @arg: PID, path or name of network namespace + * @netns: buffer of size PATH_MAX, initial contains --netns + * argument (may be empty), updated with netns path + * @arg: PID of network namespace * * Return: 0 on success, negative error code otherwise */ -static int conf_ns_opt(char *userns, char *netns, const char *arg) +static int conf_ns_pid(char *userns, char *netns, const char *arg) { char *endptr; long pidval; - int ret; + + if (*netns) { + err("Both --netns and PID given"); + return -EINVAL; + } pidval = strtol(arg, &endptr, 10); if (!*endptr) { @@ -518,20 +550,7 @@ static int conf_ns_opt(char *userns, char *netns, const char *arg) return 0; } - if (!strchr(arg, '/')) { - /* looks like a netns name */ - ret = snprintf(netns, PATH_MAX, "%s/%s", NETNS_RUN_DIR, arg); - } else { - /* otherwise assume it's a netns path */ - ret = snprintf(netns, PATH_MAX, "%s", arg); - } - - if (ret <= 0 || ret > PATH_MAX) { - err("Network namespace name/path %s too long"); - return -E2BIG; - } - - return 0; + return -EINVAL; } /** @@ -708,10 +727,13 @@ static unsigned int conf_ip6(unsigned int ifi, static void usage(const char *name) { if (strstr(name, "pasta")) { - info("Usage: %s [OPTION]... [PID|PATH|NAME]", name); + info("Usage: %s [OPTION]... [COMMAND] [ARGS]...", name); + info(" %s [OPTION]... PID", name); + info(" %s [OPTION]... --netns [PATH|NAME]", name); info(""); - info("Without PID|PATH|NAME, run the default shell in a new"); - info("network and user namespace, and connect it via pasta."); + info("Without PID or --netns, run the given command or a"); + info("default shell in a new network and user namespace, and"); + info("connect it via pasta."); } else { info("Usage: %s [OPTION]...", name); } @@ -858,6 +880,7 @@ pasta_opts: info( " SPEC is as described above"); info( " default: auto"); info( " --userns NSPATH Target user namespace to join"); + info( " --netns PATH|NAME Target network namespace to join"); info( " --netns-only Don't join existing user namespace"); info( " implied if PATH or NAME are given without --userns"); info( " --config-net Configure tap interface in namespace"); @@ -1038,6 +1061,7 @@ void conf(struct ctx *c, int argc, char **argv) {"tcp-ns", required_argument, NULL, 'T' }, {"udp-ns", required_argument, NULL, 'U' }, {"userns", required_argument, NULL, 2 }, + {"netns", required_argument, NULL, 3 }, {"netns-only", no_argument, &c->netns_only, 1 }, {"config-net", no_argument, &c->pasta_conf_ns, 1 }, {"ns-mac-addr", required_argument, NULL, 4 }, @@ -1091,6 +1115,16 @@ void conf(struct ctx *c, int argc, char **argv) usage(argv[0]); } break; + case 3: + if (c->mode != MODE_PASTA) { + err("--netns is for pasta mode only"); + usage(argv[0]); + } + + ret = conf_netns(netns, optarg); + if (ret < 0) + usage(argv[0]); + break; case 4: if (c->mode != MODE_PASTA) { err("--ns-mac-addr is for pasta mode only"); @@ -1465,11 +1499,12 @@ void conf(struct ctx *c, int argc, char **argv) check_root(c); if (c->mode == MODE_PASTA && optind + 1 == argc) { - ret = conf_ns_opt(userns, netns, argv[optind]); + ret = conf_ns_pid(userns, netns, argv[optind]); if (ret < 0) usage(argv[0]); - } else if (c->mode == MODE_PASTA && *userns && optind == argc) { - err("--userns requires PID, PATH or NAME"); + } else if (c->mode == MODE_PASTA && *userns + && !*netns && optind == argc) { + err("--userns requires --netns or PID"); usage(argv[0]); } else if (optind != argc) { usage(argv[0]); diff --git a/passt.1 b/passt.1 index bbdadc1..1f0cd47 100644 --- a/passt.1 +++ b/passt.1 @@ -15,7 +15,10 @@ [\fIOPTION\fR]... .br .B pasta -[\fIOPTION\fR]... [\fIPID\fR|\fIPATH\fR|\fINAME\fR] +[\fIOPTION\fR]... [\fIPID\fR] +.br +.B pasta +[\fIOPTION\fR]... \fB--netns\fR [\fIPATH\fR|\fINAME\fR] .SH DESCRIPTION @@ -59,7 +62,7 @@ or with the \fBqrap\fR(1) wrapper. equivalent functionality to network namespaces, as the one offered by \fBpasst\fR for virtual machines. -If PID, PATH or NAME are given, \fBpasta\fR associates to an existing user and +If PID or --netns are given, \fBpasta\fR associates to an existing user and network namespace. Otherwise, \fBpasta\fR creates a new user and network namespace, and spawns an interactive shell within this context. A \fItap\fR device within the network namespace is created to provide network connectivity. @@ -445,7 +448,14 @@ Default is \fBauto\fR. Target user namespace to join, as a path. If PID is given, without this option, the user namespace will be the one of the corresponding process. -This option requires PID, PATH or NAME to be specified. +This option requires --netns or a PID to be specified. + +.TP +.BR \-\-netns " " \fIspec +Target network namespace to join, as a path or a name. A name is treated as +with \fBip-netns(8)\fR as equivalent to a path in \fI/run/netns\fR. + +This option can't be specified with a PID. .TP .BR \-\-netns-only -- cgit v1.2.3