Skip to content
Back
Reference

Linux UDP receive sysctl reference

Tune every Linux network sysctl on the normal high-rate IPv4 UDP receive path with defaults, receiver values, and parameter-specific failure modes.

Baseline assumptions

The recommended column targets a dedicated receiver for the measured 54.3 Mbps and 5,585 packets-per-second feed. It is a starting configuration for testing, not a claim that one number fits every kernel, NIC, driver, namespace, and workload.

Linux defaults below are upstream defaults where one fixed value exists. A distribution, kernel configuration, boot-time memory calculation, container runtime, or loaded module can change the active value. Read every deployed value before applying a change.

Socket memory

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.core.rmem_defaultCurrent upstream: 256 times SKB_TRUESIZE(256), so the byte value is architecture dependent; older common builds report 212,992 bytesKeep the active default; have the application request 4,194,304 bytes with SO_RCVBUFDefault receive limit for sockets that make no requestLeaving both default and application request small causes UdpRcvbufErrors during pauses; raising the global default needlessly enlarges unrelated sockets
net.core.rmem_maxCurrent upstream: 4,194,304 bytes; older common kernels report 212,992 bytes134,217,728 bytesCeiling for an ordinary SO_RCVBUF requestToo low silently caps the requested socket buffer; far above a host memory budget permits many sockets to consume excessive kernel memory under load
net.core.optmem_max131,072 bytes131,072 bytesMaximum ancillary and option memory per socketToo low can truncate timestamp or control data under complex ancillary use; raising it does not increase UDP payload queue capacity
net.ipv4.udp_memComputed at boot from available memory, in pagesKeep the boot-computed triplet unless host-wide UDP pressure is measured and budgetedLow, pressure, and high thresholds for all UDP socket memoryA low high-threshold drives global UDP memory pressure and drops across sockets; a copied oversized triplet can expose the host to uncontrolled kernel-memory use
net.ipv4.udp_rmem_min4,096 bytes4,096 bytesMinimum receive allocation retained per UDP socket under protocol memory pressureLower values make active sockets more fragile during global pressure; raising it across many sockets reserves more pressure-time memory without fixing a slow receiver

Set net.core.rmem_max before the process creates the socket. The process should request its own SO_RCVBUF and read back the effective value. Linux commonly reports twice the requested value for socket bookkeeping, so a 4,194,304-byte request can appear as 8,388,608 bytes.

Input backlog and NAPI budgets

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.core.netdev_max_backlog1,000 packets8,192 packets on a dedicated host after a burst testMaximum per-CPU input backlog when packets arrive faster than the stack processes themToo low increments the softnet drop field during bursts; too high hides CPU starvation as older queued packets and raises cache and memory pressure
net.core.netdev_budget300 packets600 packets on a dedicated receiver, provided ingest scheduling remains inside budgetMaximum packet work in one networking poll cycleToo low raises softnet time-squeeze events and backlog; too high lets networking occupy the CPU long enough to delay the application that must drain the socket
net.core.netdev_budget_usecs2,000 microseconds2,000 microsecondsTime limit for one networking poll cycle on kernels that expose itToo low defers pending packets and grows the backlog; too high creates scheduler latency spikes for a colocated receive thread
net.core.dev_weight64 packets64 packetsBase per-NAPI poll weight used in budget accountingToo low increases repeated poll scheduling under bursts; too high lets one poller dominate a CPU and delay user space
net.core.dev_weight_rx_bias11Biases global budget toward receive softirq work relative to the base weightToo low can starve receive backlog work; too high can starve the socket consumer on the same CPU
net.core.dev_weight_tx_bias11Biases global budget toward transmit softirq workRaising it on a receive-focused host can spend the cycle on unrelated transmit work while the feed backlog grows
net.core.gro_normal_batch8 packets8 packetsBatch size for normal GRO processingToo large can increase batching delay and burst delivery into the UDP socket; too small increases per-packet stack work and can raise CPU pressure

Check the second and third fields of each row in /proc/net/softnet_stat as deltas. A backlog setting cannot repair NIC-ring drops, and a socket-buffer setting cannot repair an earlier softnet drop.

Busy polling

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.core.busy_read0 microseconds0 globally; test SO_BUSY_POLL of 50 microseconds on the receiver socketDefault busy-poll duration for blocking readsZero can leave scheduler wakeup tails; a large global value burns CPU on unrelated sockets and can starve decode workers
net.core.busy_poll0 microseconds0 globally; test 50 microseconds only on a dedicated host if per-socket control is unavailableDefault busy-poll duration for poll and select pathsToo low gives no wakeup benefit; too high can saturate a core during quiet periods without improving packet age

Busy-poll support depends on kernel, driver, NAPI association, privileges, and socket options. SO_BUSY_POLL_BUDGET and the epoll busy_poll_budget field are not sysctls and therefore are outside the table. A configured value with no compatible NAPI path can consume configuration effort while changing nothing. Measure p50, p99.9, CPU, softnet counters, socket drops, and decode age together.

Steering and timestamp placement

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.core.rps_sock_flow_entries00 for one dedicated hardware-steered feed; size only when RFS is intentionally configuredGlobal Receive Flow Steering table sizeEnabling it without per-queue flow counts adds no useful RFS placement; oversized tables consume memory, while poor steering adds cross-CPU cache movement
net.core.netdev_tstamp_prequeue11 for ordinary operation; 0 for a controlled benchmark that requires post-queue timestamp placementAllows receive timestamps before receive-packet steering and queueingA value inconsistent across compared feeds moves timestamp boundaries and invalidates a race; disabling prequeue can add queue delay to the recorded timestamp

RPS and RFS also require per-queue sysfs masks and flow counts, which are outside sysctl. On a NIC with enough hardware queues, one critical UDP tuple normally benefits from stable flow affinity more than from being moved between CPUs in software.

IPv4 demultiplexing and fragments

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.ipv4.ip_early_demux11Performs early socket lookup for supported local trafficDisabling adds later lookup work and can raise CPU cost; enabling is inappropriate only when a documented routing workload requires otherwise
net.ipv4.udp_early_demux11Enables early demultiplexing for connected UDP socketsDisabling can add receive-path lookup cost; relying on it for an unconnected listener gives no guarantee of the same fast path
net.ipv4.ipfrag_high_thresh4,194,304 bytes4,194,304 bytesMaximum memory held for IPv4 fragment reassembly before pruningToo low drops legitimate fragmented traffic; too high lets fragment floods retain more memory and CPU, while this feed should fit inside a normal 1,500-byte MTU
net.ipv4.ipfrag_low_thresh3,145,728 bytes on older kernels that expose it; absent on newer kernelsKeep the active default if presentOlder-kernel target below which fragment memory was prunedRaising it delays memory reclamation; lowering it increases reassembly failure, and tuning it cannot fix a path that fragments 1,228-byte UDP payloads unexpectedly
net.ipv4.ipfrag_time30 seconds30 secondsMaximum retention time for an incomplete IPv4 fragment queueToo long retains attack or loss debris and memory; too short drops fragments on slow paths, though normal feed datagrams should not fragment
net.ipv4.ipfrag_max_dist6464Maximum disorder distance used to detect likely unrelated fragments from one sourceToo low discards reordered legitimate fragments; too high permits more stale fragment state, while a clean shred path should avoid fragmentation

Do not raise fragment thresholds to conceal an MTU failure. With an ordinary 1,500-byte path MTU, the documented maximum UDP payload fits without IP fragmentation under the usual IPv4 and UDP headers.

Reverse-path filtering

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.ipv4.conf.all.rp_filter0 upstream; some distributions set 11 on a single-homed symmetric receiver; 2 on an intentionally asymmetric multihomed receiverGlobal reverse-path source validation modeStrict mode drops valid packets silently when the reverse route selects another interface; mode 0 accepts spoof-prone paths that policy may expect to filter
net.ipv4.conf.default.rp_filter0 upstream; distribution value can differMatch the intended policy for future interfacesTemplate applied when new interfaces appearA wrong template makes behavior change after interface recreation or reboot even when the current interface looked correct
net.ipv4.conf.INTERFACE.rp_filterInherits the default when the interface is created1 for symmetric routing or 2 for approved asymmetryInterface-specific reverse-path modeA conflicting interface value can drop 64.130.40.90 on one path while captures elsewhere appear healthy

Mode 0 disables reverse-path checks, mode 1 is strict, and mode 2 is loose. Test the actual route to 64.130.40.90 and the interface that receives the feed before selecting a mode.

Conntrack, when loaded

SysctlLinux defaultRecommended receiver valueMeaningConcrete failure when wrong
net.netfilter.nf_conntrack_maxSet from the conntrack hash size at module initializationKeep the host capacity plan with sustained count below 70 percent; use notrack for this tuple on a non-NAT dedicated receiverMaximum tracked connectionsToo low drops new flows with table-full events; too high consumes kernel memory and permits long hash chains under hostile traffic
net.netfilter.nf_conntrack_bucketsComputed from memory when the module loads, bounded by kernel minimum and maximumKeep the computed value unless bucket-chain measurements support a changeConntrack hash-table bucket countToo few buckets raise lookup CPU and latency at a given flow count; too many waste kernel memory
net.netfilter.nf_conntrack_udp_timeout30 seconds30 seconds when tracking is requiredTimeout for ordinary unassured UDP entriesToo short churns state during feed pauses or breaks NAT mappings; too long retains spoofed one-way flows and table occupancy
net.netfilter.nf_conntrack_udp_timeout_stream120 seconds120 seconds when tracking is requiredTimeout for UDP flows that have seen traffic in both directionsToo short expires bidirectional state unexpectedly; too long retains inactive assured entries
net.netfilter.nf_conntrack_checksum11Verifies incoming transport checksums before admitting packets to conntrackDisabling allows corrupt packets into state tracking; enabling adds checksum work but protects state integrity
net.netfilter.nf_conntrack_acct00 unless per-flow byte and packet counters are required for diagnosisAdds accounting counters to conntrack entriesEnabling adds per-packet accounting work and memory; disabling removes per-flow counters but not protocol or firewall counters

Conntrack sysctls exist only when the subsystem is loaded and visible in the namespace. One stable feed tuple consumes about one entry, while packet rate determines lookup work. On a receiver that performs no NAT and has a narrow stateless firewall rule, an early notrack rule can remove the feed from conntrack rather than tuning a global table around one flow.

Apply changes as experiments

StageCounter or observationSysctls that can affect it
NICDriver missed, no-buffer, discard, and queue countersNone in this scope; use driver and ethtool controls
NAPI and softnetBacklog drops and time-squeeze deltasnetdev_max_backlog, netdev_budget, netdev_budget_usecs, dev_weight fields
UDP socketUdpRcvbufErrors, per-socket drops, receive allocationrmem_max, application SO_RCVBUF, udp_mem
ApplicationQueue rejects and receive-to-decode ageNo sysctl substitutes for application capacity
Clock instrumentTimestamp boundary and uncertaintynetdev_tstamp_prequeue plus socket timestamp options
Stateful firewallConntrack count, insert_failed, drop, early_dropnf_conntrack fields

Change one layer at a time. Reboot or recreate the namespace when testing persistence. Record kernel release, active values, NIC and driver, queue mapping, receiver build, packet distribution, loss counters, CPU, and latency before and after.

Questions

Which receive-buffer values should a shred receiver start with?
On dedicated Linux hosts, keep the active net.core.rmem_default, raise net.core.rmem_max to 134,217,728 bytes, and have the application request SO_RCVBUF of 4,194,304 bytes. Read back the effective value, then validate it with controlled pauses, UdpRcvbufErrors, per-socket drops, queue residence, and catch-up time.
Should busy polling be enabled globally?
Keep net.core.busy_read and net.core.busy_poll at zero by default. On a dedicated receiver, test SO_BUSY_POLL of 50 microseconds on the target socket. A useful result lowers tail latency without socket loss or a saturated ingest core. Global settings affect unrelated sockets and can waste CPU continuously.
Can sysctl tuning eliminate UDP loss?
No. Sysctls can move or resize specific kernel queues, but they cannot repair NIC loss, an undersized driver ring, bad affinity, sustained application under-capacity, a restrictive firewall, or upstream absence. Locate the first rising drop counter, change the control for that stage, and verify packet age as well as loss.