Network buffers#

Why#

A public NTP server receives packets in bursts, especially during traffic spikes or scan attacks. The kernel’s default network buffers are sized for general-purpose use, not for absorbing these bursts without packet loss, nor for carrying the extra metadata from hardware timestamping (next chapter).

How#

cat > /etc/sysctl.d/99-ntp-buffers.conf <<'EOF'
# L3/L4 buffers (UDP packets)
net.core.rmem_max     = 33554432
net.core.wmem_max     = 33554432
net.core.rmem_default = 1048576
net.core.wmem_default = 1048576

# Auxiliary memory for hardware timestamping metadata
net.core.optmem_max   = 262144

# L2 -> L3 software queue
net.core.netdev_max_backlog = 30000

# Global UDP memory pressure
net.ipv4.udp_mem      = 65536 131072 262144
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384
EOF

sysctl --system
DirectiveMeaning
rmem_max/wmem_max = 33554432 (32 MiB)The ceiling an application can request via setsockopt(SO_RCVBUF/SNDBUF), not a default allocation: well above the viable minimum (a few MiB) to absorb a burst without loss, without weighing on RAM unless a socket actually asks for that maximum
rmem_default/wmem_default = 1048576 (1 MiB)Default buffer size when an application (like chronyd) doesn’t set its own explicitly, several times larger than Linux’s generic default (~208 KiB), to absorb traffic surges without any application-side tuning
netdev_max_backlog = 30000Maximum number of packets queued between the NIC driver and the IP stack when the CPU can’t process them fast enough (well above the default of 1000), a burst-absorption buffer before packets start getting dropped, especially useful here where a single dedicated core (IRQ affinity chapter) handles all incoming traffic
udp_mem = 65536 131072 262144 (memory pages)The three system-wide UDP memory pressure thresholds (low / pressure / high), on the same principle as tcp_mem: past the high threshold, the kernel starts reclaiming memory from existing UDP sockets
udp_rmem_min/udp_wmem_min = 16384 (16 KiB)Per-socket UDP buffer floor, raised above Linux’s default floor (4 KiB), guarantees a minimum capacity even under overall memory pressure

Pitfalls to avoid#

  • Neglecting net.core.optmem_max. This is the parameter most often forgotten in generic network tuning guides, since it has no visible effect on ordinary UDP traffic. It becomes necessary as soon as hardware timestamping is enabled (PHC chapter): each packet then carries extra metadata (cmsg, control message) through this auxiliary channel, and an optmem_max that’s too small silently truncates that metadata.
  • Copying generic tuning values without adapting them. The values above are sized for a modest-traffic public NTP server. A server with significantly higher traffic would likely need larger buffers, but an oversized buffer brings no benefit and just wastes RAM.

Verify#

sysctl net.core.rmem_max
# Should return 33554432

sysctl net.core.optmem_max
# Should return 262144

The most telling proof of this chapter’s usefulness comes later, in the Final verification chapter: the percentage of packets receiving a hardware timestamp instead of a software one directly depends on these settings.