How to Trace TCP Socket TCP_INFO tcpi_snd_ssthresh in Linux Using eBPF

Understanding when a Linux TCP connection transitions from exponential slow start to linear congestion avoidance is critical for diagnosing throughput bottlenecks on high-speed networks. The kernel struct tcp_info records tcpi_snd_ssthresh, representing the slow-start threshold in segments. Tracing this value via eBPF gives direct real-time visibility into kernel congestion state decisions.

The Role of Slow-Start Threshold (ssthresh)

TCP congestion control algorithms (such as Cubic and Reno) use ssthresh as a demarcation boundary. Below this threshold, the congestion window (snd_cwnd) doubles roughly every round-trip time. Once snd_cwnd reaches ssthresh, growth drops into linear probing. Rapid or unexpected reductions in ssthresh highlight premature packet loss or misconfigured ECN signals.

eBPF BCC Script for ssthresh Observation

The following script attaches to tcp_fastretrans_alert and tcp_enter_cwr to capture threshold shifts during congestion episodes:

from bcc import BPF

bpf_source = """
#include <net/sock.h>
#include <linux/tcp.h>

struct ssthresh_event_t {
    u32 pid;
    u16 sport;
    u16 dport;
    u32 ssthresh;
    u32 cwnd;
};

BPF_PERF_OUTPUT(thresh_events);

int trace_ssthresh(struct pt_regs *ctx, struct sock *sk) {
    if (sk->sk_family != AF_INET)
        return 0;

    struct tcp_sock *tp = tcp_sk(sk);
    struct ssthresh_event_t evt = {};

    evt.pid = bpf_get_current_pid_tgid() >> 32;
    evt.sport = sk->sk_num;
    evt.dport = bpf_ntohs(sk->sk_dport);
    evt.ssthresh = tp->snd_ssthresh;
    evt.cwnd = tp->snd_cwnd;

    thresh_events.perf_submit(ctx, &evt, sizeof(evt));
    return 0;
}
"""

b = BPF(text=bpf_source)
b.attach_kprobe(event="tcp_enter_cwr", fn_name="trace_ssthresh")

def print_thresh(cpu, data, size):
    evt = b["thresh_events"].event(data)
    print(f"PID {evt.pid:<6} | {evt.sport} -> {evt.dport} | ssthresh: {evt.ssthresh} segs | cwnd: {evt.cwnd} segs")

b["thresh_events"].open_perf_buffer(print_thresh)
print("Listening for TCP ssthresh adjustments... Press Ctrl+C to stop.")
while True:
    b.perf_buffer_poll()

Operational Analysis

Execute the monitoring probe on the target host:

sudo python3 trace_ssthresh.py

If ssthresh collapses to minimal values (e.g. 2 or 3 segments) on low-latency local links, inspect intermediate network equipment for bufferbloat or transient physical link drops.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.