How to Trace TCP Socket TCP_CC_INFO BBR Metric Telemetry in Linux Using eBPF

Google’s BBR (Bottleneck Bandwidth and RTT) congestion control algorithm operates fundamentally differently from traditional loss-based TCP algorithms. Instead of treating packet loss as an indicator of network saturation, BBR continuously models the network bottleneck by measuring two physical parameters: maximum bandwidth delivery rate (bw) and minimum round-trip time (min_rtt). While BBR delivers massive throughput gains across global WAN links, diagnosing BBR pacing anomalies, probe-RTT stalls, or packet queuing requires visibility into the kernel’s private BBR state. This tutorial demonstrates how to extract real-time BBR metrics via eBPF.

The Mechanics of TCP_CC_INFO and Kernel BBR State

When an application queries getsockopt(fd, IPPROTO_TCP, TCP_CC_INFO, &info, &len) on a socket running BBR, the kernel returns a struct tcp_bbr_info. This structure reveals:

  • bbr_bw_hi and bbr_bw_lo: Estimated delivery rate in bytes per second.
  • bbr_min_rtt: Minimum round-trip time filter measured in microseconds.
  • bbr_pacing_gain and bbr_cwnd_gain: Dynamic gain coefficients driving transmission pacing.

By hooking kernel BBR rate estimation functions (such as bbr_update_model()) using eBPF kprobes, system engineers can observe live throughput metrics across thousands of concurrent connections with negligible overhead.

Prerequisites and Environment Verification

Install the required tracing tools on your Linux workstation or server:

sudo apt-get update
sudo apt-get install -y bpftrace linux-headers-$(uname -r)

Verify that the BBR kernel module is loaded and active:

lsmod | grep bbr

Authoring the bpftrace BBR Telemetry Script

Save the following script as trace_bbr.bt to capture real-time delivery rate calculations and RTT fluctuations:

#!/usr/bin/env bpftrace

#include <net/sock.h>
#include <linux/tcp.h>

kprobe:bbr_update_model
{
    $sk = (struct sock *)arg0;
    $inet = (struct inet_sock *)arg0;

    $daddr = ntop($inet->sk.__sk_common.skc_daddr);
    $dport = bswap($inet->sk.__sk_common.skc_dport);
    $sport = bswap($inet->inet_sport);

    @bbr_active_sockets[$daddr, $dport] = count();
}

kprobe:tcp_update_pacing_rate
{
    $sk = (struct sock *)arg0;
    $tp = (struct tcp_sock *)arg0;

    // Filter high-throughput pacing updates
    if ($sk->sk_pacing_rate > 0) {
        $rate_mbps = ($sk->sk_pacing_rate * 8) / 1000000;
        @pacing_rates_mbps = hist($rate_mbps);
    }
}

interval:s:5
{
    printf("\n--- Active BBR Sockets and Pacing Rate Distribution (Mbps) ---\n");
    print(@pacing_rates_mbps);
}

END
{
    clear(@bbr_active_sockets);
}

Executing the Trace and Analyzing Telemetry

Run the monitor with administrative privileges:

sudo bpftrace trace_bbr.bt

Generate high-bandwidth TCP streams using tools like iperf3 or initiate video downloads. The log2 histogram visualizes pacing rates in real time:

--- Active BBR Sockets and Pacing Rate Distribution (Mbps) ---
[64, 128)             42 |@@                                                |
[128, 256)           380 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@|
[256, 512)           210 |@@@@@@@@@@@@@@@@@@@@@@@@@@@                       |

Consistently depressed pacing rates indicate that BBR is constrained by frequent packet reordering or receiver window bottlenecks.

Kernel Socket Optimization Guidelines

  • Verify that the fq queueing discipline is active: tc qdisc show dev eth0. Without Fair Queueing, Linux cannot pace packets accurately, causing BBR to burst prematurely.
  • Tune socket memory limits to allow pacing queues to expand: sysctl -w net.ipv4.tcp_wmem="4096 65536 16777216".

Get the best tech tips delivered straight to your inbox.

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