]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
IO: Ensure that socket rcvbuf is large enough
authorOndrej Zajicek <santiago@crfreenet.org>
Thu, 1 Aug 2024 12:55:05 +0000 (14:55 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Thu, 1 Aug 2024 12:55:05 +0000 (14:55 +0200)
The socket structure has the field rbsize (receive buffer size), which
controls the size of the userspace receive buffer. There is also kernel
receive buffer, which in some cases may be smaller (e.g. on FreeBSD it
is by default ~8k). The patch ensures that the kernel receive buffer is
as large as the userspace receive buffer.

sysdep/unix/io.c

index 987c7a6ba942ea5484a1b120d83f86ce6850cdfd..59b33ef1804e71ac62f98c21a54bc26a621e658a 100644 (file)
@@ -517,6 +517,40 @@ sk_set_high_port(sock *s UNUSED)
   return 0;
 }
 
+static inline int
+sk_set_min_rcvbuf_(sock *s, int bufsize)
+{
+  int oldsize = 0, oldsize_s = sizeof(oldsize);
+
+  if (getsockopt(s->fd, SOL_SOCKET, SO_RCVBUF, &oldsize, &oldsize_s) < 0)
+    ERR("SO_RCVBUF");
+
+  if (oldsize >= bufsize)
+    return 0;
+
+  bufsize = BIRD_ALIGN(bufsize, 64);
+  if (setsockopt(s->fd, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)) < 0)
+    ERR("SO_RCVBUF");
+
+  /*
+  int newsize = 0, newsize_s = sizeof(newsize);
+  if (getsockopt(s->fd, SOL_SOCKET, SO_RCVBUF, &newsize, &newsize_s) < 0)
+    ERR("SO_RCVBUF");
+
+  log(L_INFO "Setting rcvbuf on %s from %d to %d",
+      s->iface ? s->iface->name : "*", oldsize, newsize);
+  */
+
+  return 0;
+}
+
+static void
+sk_set_min_rcvbuf(sock *s, int bufsize)
+{
+  if (sk_set_min_rcvbuf_(s, bufsize) < 0)
+    log(L_WARN "Socket error: %s%#m", s->err);
+}
+
 static inline byte *
 sk_skip_ip_header(byte *pkt, int *len)
 {
@@ -862,6 +896,9 @@ sk_set_rbsize(sock *s, uint val)
   xfree(s->rbuf_alloc);
   s->rbuf_alloc = xmalloc(val);
   s->rpos = s->rbuf = s->rbuf_alloc;
+
+  if ((s->type == SK_UDP) || (s->type == SK_IP))
+    sk_set_min_rcvbuf(s, s->rbsize);
 }
 
 void
@@ -1058,6 +1095,9 @@ sk_setup(sock *s)
     if (sk_set_priority(s, s->priority) < 0)
       return -1;
 
+  if ((s->type == SK_UDP) || (s->type == SK_IP))
+    sk_set_min_rcvbuf(s, s->rbsize);
+
   return 0;
 }