From: Martin Schitter <ms+git@mur.at>
To: passt-dev@passt.top
Cc: Martin Schitter <ms+git@mur.at>
Subject: [PATCH 1/3] Fix handling of netlink multipart route dumps.
Date: Tue, 8 Sep 2026 16:52:22 +0000 [thread overview]
Message-ID: <20260908165322.521274-2-ms+git@mur.at> (raw)
In-Reply-To: <20260908165322.521274-1-ms+git@mur.at>
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..52c1125 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.*/
+ left = nl_collect(s_src, buf, sizeof(buf), seq);
+ if (left < 0)
+ return left;
+
+ for (nh = (struct nlmsghdr *)buf;
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
next prev parent reply other threads:[~2026-09-08 16:53 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-08 16:52 Fix for Bug #221 -- Issue concerning bigger routing tables Martin Schitter
2026-09-08 16:52 ` Martin Schitter [this message]
2026-09-08 16:52 ` [PATCH 2/3] Timekeeping: Resolving Route Dependencies Martin Schitter
2026-09-08 16:52 ` [PATCH 3/3] Optimize route dependency solver Martin Schitter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260908165322.521274-2-ms+git@mur.at \
--to=ms+git@mur.at \
--cc=passt-dev@passt.top \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://passt.top/passt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).