public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
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


  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).