From 813918daa1a56c26ecc7c3db5e79eec40b917ea8 Mon Sep 17 00:00:00 2001 From: hiroTamada <88675973+hiroTamada@users.noreply.github.com> Date: Mon, 27 Jul 2026 19:57:23 +0000 Subject: [PATCH] Request a larger receive buffer for conntrack events The conntrack event socket ran on the kernel default. Production hosts report "recv conntrack events: no buffer space available" roughly once a minute each, and every one of those is a batch of connection events the auto-standby controller never sees. A connection whose event is lost is not counted as inbound activity, so an instance still serving it looks idle. Request 40MiB, which Linux stores as 80MiB, against a net.core.rmem_default of 8MiB on those hosts. SO_RCVBUFFORCE first so the value cannot be silently clamped to net.core.rmem_max, falling back to SO_RCVBUF where CAP_NET_ADMIN is unavailable. Both failing is tolerated: a socket with the default buffer still delivers events, so sizing must not stop the subscription from opening. This reduces how often events are dropped. It does not make a drop recoverable, and it does not make the idle decision verify itself. Co-Authored-By: Claude Opus 5 --- lib/autostandby/conntrack_events_linux.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/lib/autostandby/conntrack_events_linux.go b/lib/autostandby/conntrack_events_linux.go index b2e0998b..d8b110c2 100644 --- a/lib/autostandby/conntrack_events_linux.go +++ b/lib/autostandby/conntrack_events_linux.go @@ -26,6 +26,13 @@ type conntrackStream struct { var errUnsupportedConntrackProtocol = errors.New("unsupported conntrack protocol") +// conntrackRcvBufBytes is the receive buffer requested for the conntrack event +// socket. The kernel drops events when this buffer overruns, and hosts churning +// through guests overrun the default regularly. Linux stores twice what is +// requested, so this asks for 80MiB of headroom against a net.core.rmem_default +// of 8MiB on production hosts. +const conntrackRcvBufBytes = 40 << 20 + // OpenStream subscribes to IPv4 conntrack NEW, UPDATE, and DESTROY events. func (s *ConntrackSource) OpenStream(ctx context.Context) (ConnectionStream, error) { fd, err := unix.Socket(unix.AF_NETLINK, unix.SOCK_RAW, unix.NETLINK_NETFILTER) @@ -38,6 +45,13 @@ func (s *ConntrackSource) OpenStream(ctx context.Context) (ConnectionStream, err closeFD() return nil, fmt.Errorf("bind netfilter netlink socket: %w", err) } + // SO_RCVBUFFORCE ignores net.core.rmem_max so the request cannot be silently + // clamped, but it needs CAP_NET_ADMIN. Fall back to the capped option, and + // tolerate both failing: a socket with the default buffer still delivers + // events, so buffer sizing must not stop the subscription from opening. + if err := unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUFFORCE, conntrackRcvBufBytes); err != nil { + _ = unix.SetsockoptInt(fd, unix.SOL_SOCKET, unix.SO_RCVBUF, conntrackRcvBufBytes) + } if err := unix.SetsockoptInt(fd, unix.SOL_NETLINK, unix.NETLINK_ADD_MEMBERSHIP, unix.NFNLGRP_CONNTRACK_NEW); err != nil { closeFD() return nil, fmt.Errorf("subscribe conntrack new events: %w", err)