From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from gandalf.ozlabs.org (mail.ozlabs.org [IPv6:2404:9400:2221:ea00::3]) by passt.top (Postfix) with ESMTPS id C92D15A0280 for ; Fri, 3 Nov 2023 03:23:16 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gibson.dropbear.id.au; s=201602; t=1698978187; bh=1HhEb3N+VcH0k3LCojAqSi3l26mUN8XJWkHwHtyH+F8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=XyERv16W8zwmaQSjXJhHVPqcoE7W10qKqn9F9JEqlLuLVKy1Vp93QDfIWyw2QoJq+ TE/I0EZK/cYqE5q7exys77tzlRxTpc/Pis8/9thWWrah31KTARhBTGXKMk/UCas+/c 7RATNHxrjrUU//dhCFaI79L1pFtOkcKetbVSGB08= Received: by gandalf.ozlabs.org (Postfix, from userid 1007) id 4SM4KR5vC8z4xVW; Fri, 3 Nov 2023 13:23:07 +1100 (AEDT) From: David Gibson To: passt-dev@passt.top, Stefano Brivio Subject: [PATCH v2 5/9] port_fwd: Pre-open /proc/net/* files rather than on-demand Date: Fri, 3 Nov 2023 13:22:59 +1100 Message-ID: <20231103022303.968638-6-david@gibson.dropbear.id.au> X-Mailer: git-send-email 2.41.0 In-Reply-To: <20231103022303.968638-1-david@gibson.dropbear.id.au> References: <20231103022303.968638-1-david@gibson.dropbear.id.au> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Message-ID-Hash: FNHNBIZYOEKPJW45ISBUN6H4WBDESI6V X-Message-ID-Hash: FNHNBIZYOEKPJW45ISBUN6H4WBDESI6V X-MailFrom: dgibson@gandalf.ozlabs.org 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: David Gibson 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: procfs_scan_listen() can either use an already opened fd for a /proc/net file, or it will open it. So, effectively it will open the file on the first call, then re-use the fd in subsequent calls. However, it's not possible to open the /proc/net files after we isolate our filesystem in isolate_prefork(). That means that for each /proc/net file we must call procfs_scan_listen() at least once before isolate_prefork(), or it won't work afterwards. That happens to be the case, but it's a pretty fragile requirement. To make this more robust, instead always pre-open the /proc files we will need in get_bounds_port_init() and have procfs_scan_listen() just use those. Signed-off-by: David Gibson --- port_fwd.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/port_fwd.c b/port_fwd.c index 49b60b1..045ad7a 100644 --- a/port_fwd.c +++ b/port_fwd.c @@ -29,8 +29,7 @@ /** * procfs_scan_listen() - Set bits for listening TCP or UDP sockets from procfs - * @fd: Pointer to fd for relevant /proc/net file - * @path: Path to /proc/net file to open (if fd is -1) + * @fd: fd for relevant /proc/net file * @lstate: Code for listening state to scan for * @map: Bitmap where numbers of ports in listening state will be set * @exclude: Bitmap of ports to exclude from setting (and clear) @@ -38,7 +37,7 @@ * #syscalls:pasta lseek * #syscalls:pasta ppc64le:_llseek ppc64:_llseek armv6l:_llseek armv7l:_llseek */ -static void procfs_scan_listen(int *fd, const char *path, unsigned int lstate, +static void procfs_scan_listen(int fd, unsigned int lstate, uint8_t *map, const uint8_t *exclude) { struct lineread lr; @@ -46,16 +45,12 @@ static void procfs_scan_listen(int *fd, const char *path, unsigned int lstate, unsigned int state; char *line; - if (*fd != -1) { - if (lseek(*fd, 0, SEEK_SET)) { - warn("lseek() failed on %s: %s", path, strerror(errno)); - return; - } - } else if ((*fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { + if (lseek(fd, 0, SEEK_SET)) { + warn("lseek() failed on /proc/net file: %s", strerror(errno)); return; } - lineread_init(&lr, *fd); + lineread_init(&lr, fd); lineread_get(&lr, &line); /* throw away header */ while (lineread_get(&lr, &line) > 0) { /* NOLINTNEXTLINE(cert-err34-c): != 2 if conversion fails */ @@ -96,20 +91,20 @@ void get_bound_ports(struct ctx *c, int ns, uint8_t proto) if (proto == IPPROTO_UDP) { memset(udp_map, 0, PORT_BITMAP_SIZE); - procfs_scan_listen(&c->proc_net_udp[V4][ns], "/proc/net/udp", + procfs_scan_listen(c->proc_net_udp[V4][ns], UDP_LISTEN, udp_map, udp_excl); - procfs_scan_listen(&c->proc_net_udp[V6][ns], "/proc/net/udp6", + procfs_scan_listen(c->proc_net_udp[V6][ns], UDP_LISTEN, udp_map, udp_excl); - procfs_scan_listen(&c->proc_net_tcp[V4][ns], "/proc/net/tcp", + procfs_scan_listen(c->proc_net_tcp[V4][ns], TCP_LISTEN, udp_map, udp_excl); - procfs_scan_listen(&c->proc_net_tcp[V6][ns], "/proc/net/tcp6", + procfs_scan_listen(c->proc_net_tcp[V6][ns], TCP_LISTEN, udp_map, udp_excl); } else if (proto == IPPROTO_TCP) { memset(tcp_map, 0, PORT_BITMAP_SIZE); - procfs_scan_listen(&c->proc_net_tcp[V4][ns], "/proc/net/tcp", + procfs_scan_listen(c->proc_net_tcp[V4][ns], TCP_LISTEN, tcp_map, tcp_excl); - procfs_scan_listen(&c->proc_net_tcp[V6][ns], "/proc/net/tcp6", + procfs_scan_listen(c->proc_net_tcp[V6][ns], TCP_LISTEN, tcp_map, tcp_excl); } } @@ -151,6 +146,7 @@ static int get_bound_ports_ns(void *arg) void port_fwd_init(struct ctx *c) { struct get_bound_ports_ns_arg ns_ports_arg = { .c = c }; + const int flags = O_RDONLY | O_CLOEXEC; c->proc_net_tcp[V4][0] = c->proc_net_tcp[V4][1] = -1; c->proc_net_tcp[V6][0] = c->proc_net_tcp[V6][1] = -1; @@ -158,15 +154,25 @@ void port_fwd_init(struct ctx *c) c->proc_net_udp[V6][0] = c->proc_net_udp[V6][1] = -1; if (c->tcp.fwd_in.mode == FWD_AUTO) { + c->proc_net_tcp[V4][1] = open_in_ns(c, "/proc/net/tcp", flags); + c->proc_net_tcp[V6][1] = open_in_ns(c, "/proc/net/tcp6", flags); ns_ports_arg.proto = IPPROTO_TCP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } if (c->udp.fwd_in.f.mode == FWD_AUTO) { + c->proc_net_udp[V4][1] = open_in_ns(c, "/proc/net/udp", flags); + c->proc_net_udp[V6][1] = open_in_ns(c, "/proc/net/udp6", flags); ns_ports_arg.proto = IPPROTO_UDP; NS_CALL(get_bound_ports_ns, &ns_ports_arg); } - if (c->tcp.fwd_out.mode == FWD_AUTO) + if (c->tcp.fwd_out.mode == FWD_AUTO) { + c->proc_net_tcp[V4][0] = open("/proc/net/tcp", flags); + c->proc_net_tcp[V6][0] = open("/proc/net/tcp6", flags); get_bound_ports(c, 0, IPPROTO_TCP); - if (c->udp.fwd_out.f.mode == FWD_AUTO) + } + if (c->udp.fwd_out.f.mode == FWD_AUTO) { + c->proc_net_udp[V4][0] = open("/proc/net/udp", flags); + c->proc_net_udp[V6][0] = open("/proc/net/udp6", flags); get_bound_ports(c, 0, IPPROTO_UDP); + } } -- 2.41.0