udpsocket: size socket buffers toward the OS maximum, not a fixed 1 MB

udpsocket_set_optimal_buffer_size()/_send_size() requested a fixed 1 MB
SO_RCVBUF/SO_SNDBUF and, on failure, fell back to ~200 KB. They never used
the headroom a large net.core.{r,w}mem_max provides. That headroom is what
lets a listener absorb a burst of simultaneous connections: a single
protocol thread drains one UDP socket, so when many peers establish at once
the inbound control/handshake traffic can momentarily exceed 1 MB and the
kernel silently drops the overflow, stalling the peers whose handshake
packets were lost.

Measured on a 16-core x86 listener (net.core.rmem_max = 16 MB) with 200
peers dialing in within <1 s: at the 1 MB buffer the kernel dropped 924
datagrams at the socket (Udp: RcvbufErrors) and only ~158/200 peers
completed authentication; the protocol thread sat at 9% of one core the
whole time, so it was never the bottleneck. Rebuilt with the buffer sized
to the OS maximum, the same storm dropped 0 datagrams and all peers
connected (256/256 at the 256-flow cap).

Request UDPSOCKET_SOCK_BUFSIZE_MAX (8 MB) and let the kernel clamp to
*mem_max, keeping whatever we obtain as long as it is at least the historical
1 MB floor; otherwise fall back to the ~200 KB last resort and warning
exactly as before. No API/ABI change, no new configuration, and hosts with a
small *mem_max are unaffected (they still settle at the same fallback). Also
correct the send-buffer error message to reference wmem_max instead of
rmem_max.
This commit is contained in:
Sergio Ammirata
2026-06-26 12:15:02 -04:00
parent 145b8a5fba
commit 0cf88d505a
2 changed files with 18 additions and 12 deletions
+3
View File
@@ -56,7 +56,10 @@ extern "C" {
#endif
/*** Public API ***/
/* Historical fixed target / floor for the UDP socket buffers (1 MB). */
#define UDPSOCKET_SOCK_BUFSIZE (1048576)
/* Upper target requested before the kernel clamps to net.core.{r,w}mem_max. */
#define UDPSOCKET_SOCK_BUFSIZE_MAX (8388608)
typedef struct udpsocket_url_param {
char *key;
+15 -12
View File
@@ -249,8 +249,9 @@ int udpsocket_open(uint16_t af)
int udpsocket_set_optimal_buffer_size(int sd)
{
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE;
/* Request the OS-allowed maximum; the kernel clamps to net.core.rmem_max. */
uint32_t current_recvbuf = udpsocket_get_buffer_size(sd);
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE_MAX;
if (current_recvbuf < bufsize){
setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(uint32_t));
current_recvbuf = udpsocket_get_buffer_size(sd);
@@ -261,7 +262,8 @@ int udpsocket_set_optimal_buffer_size(int sd)
}
#endif
}
if (current_recvbuf < bufsize){
/* A clamped result above the 1 MB floor is fine; only fall back below it. */
if (current_recvbuf < UDPSOCKET_SOCK_BUFSIZE){
// Settle for a smaller size
bufsize = UDPSOCKET_SOCK_BUFSIZE/5;
setsockopt(sd, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(uint32_t));
@@ -272,18 +274,19 @@ int udpsocket_set_optimal_buffer_size(int sd)
current_recvbuf = udpsocket_get_buffer_size(sd);
}
#endif
}
if (current_recvbuf < bufsize){
rist_log_priv3( RIST_LOG_ERROR, "Your UDP receive buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_recvbuf);
return -1;
if (current_recvbuf < bufsize){
rist_log_priv3( RIST_LOG_ERROR, "Your UDP receive buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_recvbuf);
return -1;
}
}
return 0;
}
int udpsocket_set_optimal_buffer_send_size(int sd)
{
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE;
/* Mirror the recv path: request the OS max, clamp to net.core.wmem_max. */
uint32_t current_sendbuf = udpsocket_get_buffer_send_size(sd);
uint32_t bufsize = UDPSOCKET_SOCK_BUFSIZE_MAX;
if (current_sendbuf < bufsize){
setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(uint32_t));
current_sendbuf = udpsocket_get_buffer_send_size(sd);
@@ -294,7 +297,7 @@ int udpsocket_set_optimal_buffer_send_size(int sd)
}
#endif
}
if (current_sendbuf < bufsize){
if (current_sendbuf < UDPSOCKET_SOCK_BUFSIZE){
// Settle for a smaller size
bufsize = UDPSOCKET_SOCK_BUFSIZE/5;
setsockopt(sd, SOL_SOCKET, SO_SNDBUF, (char *)&bufsize, sizeof(uint32_t));
@@ -305,10 +308,10 @@ int udpsocket_set_optimal_buffer_send_size(int sd)
current_sendbuf = udpsocket_get_buffer_send_size(sd);
}
#endif
}
if (current_sendbuf < bufsize){
rist_log_priv3( RIST_LOG_ERROR, "Your UDP send buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.rmem_max setting to at least 200 kbyte for best results.", current_sendbuf);
return -1;
if (current_sendbuf < bufsize){
rist_log_priv3( RIST_LOG_ERROR, "Your UDP send buffer is set < 200 kbytes (%"PRIu32") and the kernel denied our request for an increase. It's recommended to set your net.core.wmem_max setting to at least 200 kbyte for best results.", current_sendbuf);
return -1;
}
}
return 0;
}