How to Trace TCP Socket TCP_INFO tcpi_retrans_synack TCP TCP-AO Asymmetric Segment Hardware Key Rollover Window Clamp SRv6 End.DT46 Drops in Linux Using eBPF

Dual-stack enterprise backbones operating Segment Routing over IPv6 (SRv6) increasingly deploy End.DT46 (Endpoint with decapsulation and cross-connect to concurrent IPv4/IPv6 VRF routing tables) to streamline dual-stack multi-tenant virtualization. When combining dual-stack cross-connect forwarding with TCP Authentication Option (TCP-AO, RFC 5925) for multi-protocol BGP sessions, asymmetric cryptographic key rollovers can introduce packet validation discrepancies. Combined with subtle TCP receive window clamping under VRF lookup delays, these discrepancies manifest as repeated SYN-ACK retransmissions recorded in tcpi_retrans_synack within Linux struct tcp_info. Isolating these issues without degrading carrier-grade throughput necessitates extended Berkeley Packet Filter (eBPF) tracing. This tutorial outlines how to author, compile, and run an eBPF tracing workflow for SRv6 End.DT46 operations in Linux.

Kernel Fundamentals: TCP-AO and SRv6 End.DT46 Decapsulation

In modern Linux networking (kernel 6.x+), TCP-AO evaluates per-packet MAC signatures against cryptographic keychains stored in struct tcp_ao_info. During an asynchronous key rollover, if one node adopts a new key ID before its peer registers the update, SYN-ACK verification fails. The sender kernel retransmits the segment according to exponential backoff rules while logging increments to tcpi_retrans_synack.

Simultaneously, the SRv6 End.DT46 action decapsulates the outer IPv6 SRH header and executes a dual-protocol lookup inside the designated VRF table via seg6_lookup_nexthop4() or seg6_lookup_nexthop6(). If the inner IP payload experiences route flapping or if receive socket buffers lack headroom, the kernel throttles the receive window (rcv_wnd) or drops the segment inside seg6_end_dt46_action(). Capturing both the socket state and netfilter processing in real time requires targeted eBPF kprobes.

Writing the eBPF Telemetry Program

Save the following source code as trace_srv6_dt46_ao.bpf.c:

#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>

char LICENSE[] SEC("license") = "Dual BSD/GPL";

struct drop_event {
    __u32 saddr[4];
    __u32 daddr[4];
    __u16 sport;
    __u16 dport;
    __u8  retrans_synack;
    __u32 snd_wnd;
    __u32 rcv_wnd;
    __u32 drop_reason;
};

struct {
    __uint(type, BPF_MAP_TYPE_RINGBUF);
    __uint(max_entries, 1 << 24);
} events SEC(".maps");

SEC("kprobe/tcp_rtx_synack")
int BPF_KPROBE(trace_tcp_rtx_synack, struct sock *sk, struct request_sock *req)
{
    struct tcp_sock *tp = (struct tcp_sock *)sk;
    struct drop_event *e;

    e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
    if (!e)
        return 0;

    e->sport = BPF_CORE_READ(sk, __sk_common.skc_num);
    e->dport = BPF_CORE_READ(sk, __sk_common.skc_dport);
    e->retrans_synack = BPF_CORE_READ(tp, total_retrans);
    e->snd_wnd = BPF_CORE_READ(tp, snd_wnd);
    e->rcv_wnd = BPF_CORE_READ(tp, rcv_wnd);
    e->drop_reason = 1001; // Key rollover mismatch

    bpf_ringbuf_submit(e, 0);
    return 0;
}

SEC("kprobe/seg6_end_dt46_action")
int BPF_KPROBE(trace_seg6_dt46, struct sk_buff *skb)
{
    __u32 len = BPF_CORE_READ(skb, len);
    if (len > 1460) {
        struct drop_event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
        if (e) {
            e->drop_reason = 1002; // End.DT46 MTU / VRF route drop
            bpf_ringbuf_submit(e, 0);
        }
    }
    return 0;
}

Compiling and Loading the eBPF Program

Compile the BPF object file using Clang and load it into the kernel via bpftool:

# Install build dependencies
sudo apt-get install -y clang llvm libbpf-dev linux-tools-common linux-tools-$(uname -r)

# Compile bytecode
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -c trace_srv6_dt46_ao.bpf.c -o trace_srv6_dt46_ao.bpf.o

# Load probe into kernel
bpftool prog load trace_srv6_dt46_ao.bpf.o /sys/fs/bpf/trace_srv6_dt46_ao type kprobe

Observing Kernel Ring Buffer Events

Stream decoded JSON events directly from the eBPF ring buffer:

# Stream decoded ringbuffer events
sudo bpftool map dump name events -j | jq '.[] | {sport: .value.sport, dport: .value.dport, retrans: .value.retrans_synack, reason: .value.drop_reason}'

Diagnostic Reference for SRv6 End.DT46 Drops

Observed Event Probable Root Cause Remediation Procedure
Reason 1001 (SYN-ACK Retrans) Asymmetric TCP-AO key negotiation discrepancy Verify active keyrings in ip tcp_metrics and coordinate peer rollover
Reason 1002 (DT46 MTU Drop) Decapsulated frame size exceeds target VRF interface MTU Clamp TCP MSS to 1380 bytes using iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Receive window collapse VRF fib routing table contention under high packet rate Tune net.core.netdev_max_backlog and net.ipv4.tcp_rmem

Using this eBPF tracing workflow provides clear operational visibility into cryptographic session maintenance and dual-stack segment-routed packet processing on modern Linux distributions.

Get the best tech tips delivered straight to your inbox.

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