From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by passt.top (Postfix) with ESMTP id 3D6F85A005E for ; Wed, 1 Feb 2023 19:04:19 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1675274658; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=v9/ldidm95lkLYNr1qfF0SXgQO7frIP7gG536v8Wia8=; b=SSqG4GwRscTNpK1f7NBEOeiN15Ipm58+x8Qy0RppIAASavSBFo/vYzV/EzWCyYrwjEbWys mKTkQIS2pGq1gMv6Lz+SvlasMNxNY4OVngvJ8+t/3o0virBvAmP40I6SmXRENs/IjJ9oGy W9igyXp0xwPbxbCwjvuu9lY2EC5Glj4= Received: from mimecast-mx02.redhat.com (mimecast-mx02.redhat.com [66.187.233.88]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-669-n-D797ljOn2gcdPljmBzsw-1; Wed, 01 Feb 2023 13:04:14 -0500 X-MC-Unique: n-D797ljOn2gcdPljmBzsw-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.rdu2.redhat.com [10.11.54.8]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 0F8AC887400 for ; Wed, 1 Feb 2023 18:04:14 +0000 (UTC) Received: from pholzing-fedora.redhat.com (unknown [10.2.16.51]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7F567C15BA0; Wed, 1 Feb 2023 18:04:13 +0000 (UTC) From: Paul Holzinger To: passt-dev@passt.top Subject: [PATCH] pasta: wait for netns setup before calling exec Date: Wed, 1 Feb 2023 19:01:16 +0100 Message-Id: <20230201180116.21281-1-pholzing@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.1 on 10.11.54.8 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: 8bit Content-Type: text/plain; charset="US-ASCII"; x-default=true X-MailFrom: pholzing@redhat.com X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation Message-ID-Hash: WKN3MH2GMI7HKZDLSNGULLLRVAXBGOQ2 X-Message-ID-Hash: WKN3MH2GMI7HKZDLSNGULLLRVAXBGOQ2 X-Mailman-Approved-At: Thu, 02 Feb 2023 10:54:29 +0100 CC: Paul Holzinger X-Mailman-Version: 3.3.3 Precedence: list List-Id: Development discussion and patches for passt Archived-At: Archived-At: List-Archive: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: When a user spawns a command with pasta they expect the network to be ready. Currently this does not work because pasta will fork/exec before it will setup the network config. This patch fixes it by using a pipe to sync parent and child. The child will now block reading from this pipe before the exec call. The parent will then unblock the child only after the netns was configured. A command like `pasta --config-net -- ping -c1 1.1.1.1` can now actually work as expected. Signed-off-by: Paul Holzinger --- passt.c | 9 ++++++++- passt.h | 3 +++ pasta.c | 31 ++++++++++++++++++++++++++++--- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/passt.c b/passt.c index 8b2c50d..4ef5797 100644 --- a/passt.c +++ b/passt.c @@ -187,7 +187,8 @@ int main(int argc, char **argv) isolate_initial(); - c.pasta_netns_fd = c.fd_tap = c.fd_tap_listen = -1; + c.pasta_netns_fd = c.pasta_command_ready_fd = + c.fd_tap = c.fd_tap_listen = -1; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; @@ -296,6 +297,12 @@ int main(int argc, char **argv) exit(EXIT_FAILURE); } + /* start pasta child process now after the netns is setup */ + if (c.pasta_command_ready_fd > -1) { + /* close causes EOF for the read in the child so no need to write() */ + close(c.pasta_command_ready_fd); + } + if (!c.foreground) __daemon(pidfile_fd, devnull_fd); else diff --git a/passt.h b/passt.h index 3d7e567..a78cd81 100644 --- a/passt.h +++ b/passt.h @@ -154,6 +154,8 @@ struct ip6_ctx { * @pcap: Path for packet capture file * @pid_file: Path to PID file, empty string if not configured * @pasta_netns_fd: File descriptor for network namespace in pasta mode + * @pasta_command_ready_fd: File descriptor for the ready pipe to + * start child cmd, -1 if not used * @no_netns_quit: In pasta mode, don't exit if fs-bound namespace is gone * @netns_base: Base name for fs-bound namespace, if any, in pasta mode * @netns_dir: Directory of fs-bound namespace, if any, in pasta mode @@ -205,6 +207,7 @@ struct ctx { int one_off; int pasta_netns_fd; + int pasta_command_ready_fd; int no_netns_quit; char netns_base[PATH_MAX]; diff --git a/pasta.c b/pasta.c index 528f02a..56ac326 100644 --- a/pasta.c +++ b/pasta.c @@ -149,16 +149,19 @@ void pasta_open_ns(struct ctx *c, const char *netns) /** * struct pasta_spawn_cmd_arg - Argument for pasta_spawn_cmd() - * @exe: Executable to run - * @argv: Command and arguments to run + * @exe: Executable to run + * @argv: Command and arguments to run + * @ready_pipe: Ready pipe pair from parent. */ struct pasta_spawn_cmd_arg { const char *exe; char *const *argv; + int ready_pipe[2]; }; /** - * pasta_spawn_cmd() - Prepare new netns, start command or shell + * pasta_spawn_cmd() - Prepare new netns, spawn child, wait for parent, + * then exec command or shell * @arg: See @pasta_spawn_cmd_arg * * Return: this function never returns @@ -166,11 +169,24 @@ struct pasta_spawn_cmd_arg { static int pasta_spawn_cmd(void *arg) { const struct pasta_spawn_cmd_arg *a; + char buf[1]; if (write_file("/proc/sys/net/ipv4/ping_group_range", "0 0")) warn("Cannot set ping_group_range, ICMP requests might fail"); a = (const struct pasta_spawn_cmd_arg *)arg; + + /* close write side, we want read to return EOF when parent closes the fd */ + close(a->ready_pipe[1]); + + /* wait here for parent setup to finish before we exec */ + if (TEMP_FAILURE_RETRY(read(a->ready_pipe[0], buf, sizeof(buf))) < 0) { + err("Failed to read ready pipe from parent: %s", + strerror(errno)); + exit(EXIT_FAILURE); + } + close(a->ready_pipe[0]); + execvp(a->exe, a->argv); perror("execvp"); @@ -226,6 +242,13 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid, arg.argv = sh_argv; } + if (pipe(arg.ready_pipe) < 0) { + err("Create ready pipe: %s", strerror(errno)); + exit(EXIT_FAILURE); + } + + c->pasta_command_ready_fd = arg.ready_pipe[1]; + pasta_child_pid = do_clone(pasta_spawn_cmd, ns_fn_stack, sizeof(ns_fn_stack), CLONE_NEWIPC | CLONE_NEWPID | CLONE_NEWNET | @@ -237,6 +260,8 @@ void pasta_start_ns(struct ctx *c, uid_t uid, gid_t gid, exit(EXIT_FAILURE); } + close(arg.ready_pipe[0]); + NS_CALL(pasta_wait_for_ns, c); } -- 2.39.1