From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ej1-x632.google.com (mail-ej1-x632.google.com [IPv6:2a00:1450:4864:20::632]) by passt.top (Postfix) with ESMTPS id 172FB5A026D for ; Mon, 18 Sep 2023 15:37:27 +0200 (CEST) Received: by mail-ej1-x632.google.com with SMTP id a640c23a62f3a-9ada2e6e75fso598263466b.2 for ; Mon, 18 Sep 2023 06:37:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1695044246; x=1695649046; darn=passt.top; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=bXeD6O33m8PdJKkOI+MvakTQgHSezD0B5Zknq5daMuw=; b=k3To58ZpKJnVEVOdMCD+BqNyNrcTLqhZgxkY4zFIkbsPpDsrtk7EBuYmbrlIOhg4aU uA35CV5Jyc7Df3OERIoUXat1SJhvkLYEFFq8My1iWgMQzOVUnwXL11dw9i9+6jTRMvEQ Kyy06XmEimcY0/TOt3WWQZSg9cOROeqBPalx5GGWdkPk+cnWTpPnJh/qYltFJVUnQsNv OAlHvzj/XnDq7Jm+5fq0CJxANBru0JKDH4qwtDYO7lVsOvIc+rkk9FNps4up8hYvkfuX RfcNh42ySLfEvPzw4zlwOUdnfAcGSsBrPi0NEEYn/uaO7b7MZgE+wKwnP8QE1SaGEhLG B/Ew== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695044246; x=1695649046; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bXeD6O33m8PdJKkOI+MvakTQgHSezD0B5Zknq5daMuw=; b=R153AW74nFZN01LrYTKuQUlmKiKOIC0lga1hZkMjPwN71efR3fEYlR8p3FIxPe8A6h jAOnKCr5hguyamZ4ya4AOaSljNYMiildVaOwZGmhFxgfwrz8eSxUvRZb9SjqK4E/ElNx nc2U7dXiEqz8PkyLWq+wNVjzR8XTH9ZackdeB/G38fxXES9UpOn9zyX9W4zn3U44VEN/ M0LS1bFHEPw1pYcZyW7Lx60x0kPsR1hqozHy3WZ8PffnL73v7ZxUFvBx4sqni2IDzQjP Xu6FYA6fassjCbXVsjw6PA8m0vR8AVt5OcorDIQD5Na8EY5hljAVS8xLC/HqQInxLW+q bGWw== X-Gm-Message-State: AOJu0YyIGro5ZBtLlyqVtJ68nM0D2Z02C8cMdELW2Lu+YFcqkwJhln6u 8wPpxl5nZWstO5qNv/LcrpUFTWol3NA= X-Google-Smtp-Source: AGHT+IEooa3VeYUaAWxvMm2LPGPBD6GTO1ApsCuK/a3ZuOdw0zRU3D9XyCaMKVLGHowDCLqbFODEGA== X-Received: by 2002:a17:906:8a73:b0:9ad:f87c:57a8 with SMTP id hy19-20020a1709068a7300b009adf87c57a8mr4539792ejc.3.1695044246264; Mon, 18 Sep 2023 06:37:26 -0700 (PDT) Received: from localhost.localdomain ([37.252.81.99]) by smtp.gmail.com with ESMTPSA id g11-20020a170906198b00b009926928d486sm6443933ejd.35.2023.09.18.06.37.25 (version=TLS1_3 cipher=TLS_CHACHA20_POLY1305_SHA256 bits=256/256); Mon, 18 Sep 2023 06:37:25 -0700 (PDT) From: Nikolay Edigaryev To: passt-dev@passt.top Subject: [PATCH] passt: introduce --tap-fd to allow passing TAP file descriptor Date: Mon, 18 Sep 2023 17:37:21 +0400 Message-Id: <20230918133721.5130-1-edigaryev@gmail.com> X-Mailer: git-send-email 2.39.2 (Apple Git-144) In-Reply-To: <20230916143241.2a7b6c77@elisabeth> References: <20230916143241.2a7b6c77@elisabeth> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: BK6BIAJRSFPHRE3Y6VFEHIQLDQEHMVT7 X-Message-ID-Hash: BK6BIAJRSFPHRE3Y6VFEHIQLDQEHMVT7 X-MailFrom: edigaryev@gmail.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header CC: Nikolay Edigaryev X-Mailman-Version: 3.3.8 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: Problem: I have a Cloud Hypervisor virtual machine that needs both (1) an internet access without fiddling with iptables/Netfilter and (2) VM <-> host access (to be able to provision this VM over SSH without dealing with passt port forwarding, as it doesn't seem to be possible to map the whole IP address, yet the users expect an IP instead of IP:port combination). Requirement #1 is why I've choosen passt and it's pretty much satisfied (thank you for this great piece of software!). Requirement #2 implies some kind of bridge interface on the host with one TAP interface for the VM and the other for the passt. However, only pasta can accept TAP interface FD's in it's -F/--fd, which is OK, but it also configures unneeded namespacing, which in turn results in unneeded complexity and performance overhead due to the need of involving veth pairs to break away from the pasta namespace to the host for the requirement #2 to be satisfied. I've also considered proxying the UNIX domain socket communication to/from a TAP interface in my own Golang code, but it incurs significant performance overhead. On the other hand passt seems to already can do everything I need, it just needs some guidance on which type of FD it's dealing with. Solution: introduce --tap-fd command-line flag to tell passt that we're passing a TAP FD instead of a UNIX domain socket FD, which will in turn use appropriate system calls and offset calculaton for that FD. This patch also clarifies the -F/--fd description for pasta to note that we're expecting a TAP device and not a UNIX domain socket. Signed-off-by: Nikolay Edigaryev --- README.md | 5 +++++ conf.c | 37 ++++++++++++++++++++++++++++++++++--- passt.c | 2 ++ passt.h | 1 + tap.c | 8 +++++--- tap.h | 4 ++-- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 6d00313..760720c 100644 --- a/README.md +++ b/README.md @@ -381,6 +381,11 @@ descriptor that's already opened. This approach, compared to using a _tap_ device, doesn't require any security capabilities, as we don't need to create any interface. +However, if you already have a _tap_ device opened by other means, you can +pass it in the `--tap-fd` command-line option and _passt_ will use correct +system calls and won't send or expect additional QEMU-specific headers for +each packet as it does with the UNIX domain socket. + _pasta_ runs out of the box with any recent (post-3.8) Linux kernel. ## Services diff --git a/conf.c b/conf.c index 0ad6e23..b182904 100644 --- a/conf.c +++ b/conf.c @@ -803,7 +803,12 @@ static void print_usage(const char *name, int status) UNIX_SOCK_PATH, 1); } - info( " -F, --fd FD Use FD as pre-opened connected socket"); + if (strstr(name, "pasta")) { + info( " -F, --fd FD Use FD as pre-opened TAP device"); + } else { + info( " -F, --fd FD Use FD as pre-opened and connected UNIX domain socket"); + info( " --tap-fd Use FD as pre-opened TAP device"); + } info( " -p, --pcap FILE Log tap-facing traffic to pcap file"); info( " -P, --pid FILE Write own PID to the given file"); info( " -m, --mtu MTU Assign MTU via DHCP/NDP"); @@ -1232,6 +1237,7 @@ void conf(struct ctx *c, int argc, char **argv) {"config-net", no_argument, NULL, 17 }, {"no-copy-routes", no_argument, NULL, 18 }, {"no-copy-addrs", no_argument, NULL, 19 }, + {"tap-fd", required_argument, NULL, 20 }, { 0 }, }; struct get_bound_ports_ns_arg ns_ports_arg = { .c = c }; @@ -1410,6 +1416,27 @@ void conf(struct ctx *c, int argc, char **argv) warn("--no-copy-addrs will be dropped soon"); c->no_copy_addrs = copy_addrs_opt = true; + break; + case 20: + if (c->mode != MODE_PASST) + die("--tap-fd is for passt mode only"); + + if (c->fd_tap >= 0) { + if (c->mode == MODE_PASTA) + die("Multiple --fd options given"); + else + die("Multiple --fd/--tap-fd options given"); + } + + errno = 0; + c->fd_tap = strtol(optarg, NULL, 0); + + if (c->fd_tap < 0 || errno) + die("Invalid --tap-fd: %s", optarg); + + c->one_off = true; + c->fd_tap_is_socket = false; + break; case 'd': if (c->debug) @@ -1464,8 +1491,12 @@ void conf(struct ctx *c, int argc, char **argv) break; case 'F': - if (c->fd_tap >= 0) - die("Multiple --fd options given"); + if (c->fd_tap >= 0) { + if (c->mode == MODE_PASTA) + die("Multiple --fd options given"); + else + die("Multiple --fd/--tap-fd options given"); + } errno = 0; c->fd_tap = strtol(optarg, NULL, 0); diff --git a/passt.c b/passt.c index 8ddd9b3..b7276ff 100644 --- a/passt.c +++ b/passt.c @@ -195,9 +195,11 @@ int main(int argc, char **argv) } c.mode = MODE_PASTA; + c.fd_tap_is_socket = false; log_name = "pasta"; } else if (strstr(name, "passt")) { c.mode = MODE_PASST; + c.fd_tap_is_socket = true; log_name = "passt"; } else { exit(EXIT_FAILURE); diff --git a/passt.h b/passt.h index 282bd1a..2079cd0 100644 --- a/passt.h +++ b/passt.h @@ -264,6 +264,7 @@ struct ctx { int epollfd; int fd_tap_listen; int fd_tap; + bool fd_tap_is_socket; unsigned char mac[ETH_ALEN]; unsigned char mac_guest[ETH_ALEN]; diff --git a/tap.c b/tap.c index 93db989..12b66ca 100644 --- a/tap.c +++ b/tap.c @@ -76,7 +76,7 @@ int tap_send(const struct ctx *c, const void *data, size_t len) { pcap(data, len); - if (c->mode == MODE_PASST) { + if (c->fd_tap_is_socket) { int flags = MSG_NOSIGNAL | MSG_DONTWAIT; uint32_t vnet_len = htonl(len); @@ -421,7 +421,7 @@ void tap_send_frames(struct ctx *c, const struct iovec *iov, size_t n) if (!n) return; - if (c->mode == MODE_PASST) + if (c->fd_tap_is_socket) m = tap_send_frames_passt(c, iov, n); else m = tap_send_frames_pasta(c, iov, n); @@ -1176,6 +1176,7 @@ void tap_listen_handler(struct ctx *c, uint32_t events) } c->fd_tap = accept4(c->fd_tap_listen, NULL, NULL, 0); + c->fd_tap_is_socket = true; if (!getsockopt(c->fd_tap, SOL_SOCKET, SO_PEERCRED, &ucred, &len)) info("accepted connection from PID %i", ucred.pid); @@ -1225,6 +1226,7 @@ static int tap_ns_tun(void *arg) die("Tap device opened but no network interface found"); c->fd_tap = fd; + c->fd_tap_is_socket = false; return 0; } @@ -1273,7 +1275,7 @@ void tap_sock_init(struct ctx *c) ASSERT(c->one_off); ref.fd = c->fd_tap; - if (c->mode == MODE_PASST) + if (c->fd_tap_is_socket) ref.type = EPOLL_TYPE_TAP_PASST; else ref.type = EPOLL_TYPE_TAP_PASTA; diff --git a/tap.h b/tap.h index 021fb7c..3626e49 100644 --- a/tap.h +++ b/tap.h @@ -20,7 +20,7 @@ struct tap_hdr { static inline size_t tap_hdr_len_(const struct ctx *c) { - if (c->mode == MODE_PASST) + if (c->fd_tap_is_socket) return sizeof(struct tap_hdr); else return sizeof(struct ethhdr); @@ -52,7 +52,7 @@ static inline void *tap_iov_base(const struct ctx *c, struct tap_hdr *taph) static inline size_t tap_iov_len(const struct ctx *c, struct tap_hdr *taph, size_t plen) { - if (c->mode == MODE_PASST) + if (c->fd_tap_is_socket) taph->vnet_len = htonl(plen + sizeof(taph->eh)); return plen + tap_hdr_len_(c); } -- 2.39.2 (Apple Git-144)