From mboxrd@z Thu Jan 1 00:00:00 1970 Authentication-Results: passt.top; dmarc=pass (p=none dis=none) header.from=mur.at Authentication-Results: passt.top; dkim=pass (3072-bit key; unprotected) header.d=mur.at header.i=@mur.at header.a=rsa-sha256 header.s=dkim2 header.b=C/wPsyjC; dkim-atps=neutral Received: from efeu.mur.at (efeu.mur.at [89.106.208.42]) by passt.top (Postfix) with ESMTPS id 6E35B5A0275 for ; Tue, 08 Sep 2026 20:16:57 +0200 (CEST) Received: from raspi4 (lan1.raspi.ma39.ffgraz.net [10.12.1.243]) by efeu.mur.at (Postfix) with ESMTPSA id F403246F23; Tue, 8 Sep 2026 20:16:56 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=mur.at; s=dkim2; t=1788891417; bh=qAPFfCnKVOsJ4IOJ+zVj42PzLqEAx/kiE2/lMl4sQVY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=C/wPsyjC5XeSZ5Nw+Yg5+DT8ImG4c9bsIKrhOVwBQgGrlEd1Nmsc2kYMbR/4ZVXQl e9zmxK44Wnl8zCuWm5g3LjVCuK/OkGQjcrQ1GQGBXVGxlzzGMEgzpAFOQBtUUbqofp jFEQu1kXkD4IAOppxuPop9GCp0FaZYIlJm2kOYkMTi02bfuHwoDoR2LEltGTkZWgeP HLJ5hg9O7mrU+PJqc+V6VYITzjByaWDD7a5Tgg8mLHxWa4l1MBwsCYxX2Tt1VOPzXN R1LUzGFCzhZXzBq8CASwC9NOabGEu/arKaVBaQVV6h+emgVLy8XhLGLE2RHulnkQMT 1N0HoBowUJyNPHY4hhScjaLnqu7nhLOnNai/afxEbFlu3E0xBf0mTu8UMXZSSalnur gvCRD/FmTqnbKkNQwB39JUeoHX6+dJYss1oUEopPq/nf+uSUqcXK6v3QZmqE5xaEuW QVJQJ9NCiGqHctjlkH7XIallJn+T1MI+I8jS457Rx6rkvlYACSC From: Martin Schitter To: passt-dev@passt.top Subject: [PATCH v2 1/3] Fix handling of netlink multipart route dumps. Date: Tue, 8 Sep 2026 18:13:12 +0000 Message-ID: <20260908181631.537802-2-ms+git@mur.at> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260908181631.537802-1-ms+git@mur.at> References: <20260908181631.537802-1-ms+git@mur.at> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-MailFrom: ms+git@mur.at X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation Message-ID-Hash: DFYMYIAO7CKOXYPC7XLUPPYAOMAUZTKY X-Message-ID-Hash: DFYMYIAO7CKOXYPC7XLUPPYAOMAUZTKY X-Mailman-Approved-At: Tue, 08 Sep 2026 22:39:37 +0200 CC: Martin Schitter 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: This patch adds a `nl_collect` function to store all datagram chunks of a multipart route dump in one single interim buffer for further processing and dependency resolution. --- netlink.c | 79 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 56 insertions(+), 23 deletions(-) diff --git a/netlink.c b/netlink.c index 225b666..650a6fd 100644 --- a/netlink.c +++ b/netlink.c @@ -229,6 +229,51 @@ static struct nlmsghdr *nl_next(int s, char *buf, struct nlmsghdr *nh, ssize_t * /* NOLINTNEXTLINE(readability-inconsistent-ifelse-braces) */\ } else +/** + * nl_collect() - Collect all respose Datagrams of a netlink multi part dump + * @s: Netlink socket + * @buf: Buffer for responses (at least NLBUFSIZ long) + * @buflen: Buffer size. + * @seq: Sequence number of request we're getting responses for + * + * Return: Length of collected responses in bytes or error code < 0 + */ +int nl_collect(int s, char *buf, size_t buflen, uint32_t seq) +{ + size_t collected = 0; + struct nlmsghdr *nh; + ssize_t n; + int res; + const struct nlmsghdr* tail; + + #define NLMSG_DONE_SIZE NLMSG_LENGTH(4) + + while(collected + NLBUFSIZ < buflen){ + nh = nl_next(s, &buf[collected], NULL, &n); + debug("collect: add chunk of size n=%ld at offset=%ld, seq=%d nlmsg_len=%d", + n, collected, seq, ((const struct nlmsghdr *)&buf[collected])->nlmsg_len); + res = nl_status(nh, n, seq); + if (res < 0) /* error */ + return res; + collected += n; + + /* look for NLMSG_DONE -- it's ussualy transmitted in a seperate datagram, + * but in some rare cases also placed at the end of a multipart chunk.*/ + tail = (const struct nlmsghdr*)&buf[collected - NLMSG_DONE_SIZE]; + if (res == 0 || ( + collected >= NLMSG_DONE_SIZE + && (tail = (const struct nlmsghdr*)&buf[collected - NLMSG_DONE_SIZE]) + && NLMSG_OK(tail, NLMSG_DONE_SIZE) + && (nl_status(tail, NLMSG_DONE_SIZE, seq) == 0)) + ) { + debug("collected: %ld", collected); + return collected; + } + } + err("netlink: Too many routes to duplicate"); + return -E2BIG; +} + /** * nl_do() - Send netlink "do" request, and wait for acknowledgement * @s: Netlink socket @@ -553,21 +598,21 @@ int nl_route_dup(int s_src, unsigned int ifi_src, .rta.rta_len = RTA_LENGTH(sizeof(unsigned int)), .ifi = ifi_src, }; - ssize_t nlmsgs_size, left, status; + ssize_t nlmsgs_size, left, status = 0; unsigned dup_routes = 0; struct nlmsghdr *nh; - char buf[NLBUFSIZ]; + char buf[NLBUFSIZ * 8]; uint32_t seq; unsigned i; seq = nl_send(s_src, &req, RTM_GETROUTE, NLM_F_DUMP, sizeof(req)); - /* nl_foreach() will step through multiple response datagrams, - * which we don't want here because we need to have all the - * routes in the buffer at once. - */ - nh = nl_next(s_src, buf, NULL, &nlmsgs_size); - for (left = nlmsgs_size; + /* collect all the chunks of a multi part dump in one buffer.*/ + nlmsgs_size = nl_collect(s_src, buf, sizeof(buf), seq); + if (nlmsgs_size < 0) + return nlmsgs_size; + + for (nh = (struct nlmsghdr *)buf, left = nlmsgs_size; NLMSG_OK(nh, left) && (status = nl_status(nh, left, seq)) > 0; nh = NLMSG_NEXT(nh, left)) { struct rtmsg *rtm = (struct rtmsg *)NLMSG_DATA(nh); @@ -648,24 +693,12 @@ int nl_route_dup(int s_src, unsigned int ifi_src, dup_routes++; } - if (!NLMSG_OK(nh, left)) { - /* Process any remaining datagrams in a different - * buffer so we don't overwrite the first one. - */ - char tail[NLBUFSIZ]; - unsigned extra = 0; - - nl_foreach_oftype(nh, status, s_src, tail, seq, RTM_NEWROUTE) - extra++; - - if (extra) { - err("netlink: Too many routes to duplicate"); - return -E2BIG; - } - } + /* status should be 0 (=NLMSG_DONE) */ if (status < 0) return status; + debug("found %d routes in dump", dup_routes); + /* Routes might have dependencies between each other, and the kernel * processes RTM_NEWROUTE messages sequentially. For n routes, we might * need to send the requests up to n times to get all of them inserted. -- 2.53.0