Foo-over-UDP (FoU) is a high-performance encapsulation protocol designed to tunnel existing network protocols (such as IP-in-IP, SIT, and GRE) inside standard UDP datagrams, allowing legacy encapsulation formats to benefit from Receive Side Scaling (RSS) and ECMP hashing on commodity switches. When mission-critical control-plane connections—such as BGP or telemetry sockets—are authenticated using RFC 5925 TCP Authentication Option (TCP-AO) over FoU tunnel encapsulation, subtle operational anomalies can emerge. Specifically, during automated hardware cryptographic key rollovers where intermediate routers enforce dynamic TCP receive window clamping, SYN-ACK retransmissions (recorded via tcpi_retrans_synack in the kernel’s tcp_info structure) can escalate rapidly, causing silent packet discards. This technical guide explains how to construct and deploy an eBPF tracing tool to diagnose, capture, and resolve these encapsulated drops in the Linux kernel.
Protocol Mechanics: TCP-AO Key Rollovers and FoU Encapsulation
RFC 5925 TCP-AO replaces legacy MD5 authentication by supporting dynamic Master Key Tuples (MKTs) that decouple authentication credentials from active socket sessions. Each MKT defines a Send Key ID (KeyID) and Receive Next Key ID (RNextKeyID). During an automated rollover, an asymmetric routing topology can deliver ingress packets bearing a newly minted KeyID before the hardware cryptographic engine completes programming the matching security association.
When combined with FoU encapsulation, inner packets acquire an outer UDP header (typically 8 bytes) alongside an outer IP header. If a bottleneck along the path experiences transient queue congestion, routers may apply TCP receive window clamping to restrict sender buffers. When inner TCP segments encounter both key verification delays and restrictive window clamping during decap processing, the kernel TCP stack drops the segment prior to handshake completion, resulting in spiraling tcpi_retrans_synack counts.
Developing the eBPF Tracing Probe
Standard networking monitoring tools cannot capture transient drops occurring at microsecond intervals. By attaching an eBPF kprobe to tcp_ao_verify_hash and sampling socket telemetry from struct tcp_sock, we achieve fine-grained, in-kernel visibility:
// File: fou_tcp_ao_trace.bpf.c
#include <vmlinux.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_core_read.h>
#include <bpf/bpf_tracing.h>
struct drop_telemetry_t {
u32 saddr;
u32 daddr;
u16 sport;
u16 dport;
u32 retrans_synack;
u32 snd_wnd;
u32 rcv_wnd;
u8 key_id;
u8 rnext_key_id;
};
struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u32));
} fou_events SEC(".maps");
SEC("kprobe/tcp_ao_verify_hash")
int BPF_KPROBE(trace_fou_tcp_ao, struct sock *sk, struct sk_buff *skb, struct tcp_ao_key *key) {
struct tcp_sock *tp = (struct tcp_sock *)sk;
u32 retrans = BPF_CORE_READ(tp, total_retrans);
if (retrans > 0) {
struct drop_telemetry_t data = {};
data.sport = BPF_CORE_READ(sk, __sk_common.skc_num);
data.dport = bpf_ntohs(BPF_CORE_READ(sk, __sk_common.skc_dport));
data.retrans_synack = BPF_CORE_READ(tp, tcpi_retrans_synack);
data.snd_wnd = BPF_CORE_READ(tp, snd_wnd);
data.rcv_wnd = BPF_CORE_READ(tp, rcv_wnd);
bpf_perf_event_output(ctx, &fou_events, BPF_F_CURRENT_CPU, &data, sizeof(data));
}
return 0;
}
char LICENSE[] SEC("license") = "GPL";
Compiling and Loading the eBPF Module
Compile the eBPF source into object bytecode using Clang/LLVM and attach it to the kernel kprobe infrastructure using bpftool:
# Compile the eBPF probe
clang -g -O2 -target bpf -D__TARGET_ARCH_x86 -c fou_tcp_ao_trace.bpf.c -o fou_tcp_ao_trace.bpf.o
# Load and attach via bpftool
bpftool prog load fou_tcp_ao_trace.bpf.o /sys/fs/bpf/fou_tcp_ao_trace type kprobe
bpftool attach kprobe name tcp_ao_verify_hash pinned /sys/fs/bpf/fou_tcp_ao_trace
Diagnostic Analysis and Kernel Remediation
When the userland reader reports spikes in retrans_synack during key rollover windows, implement the following operational mitigations:
- FoU MTU and MSS Clamping: Encapsulation overhead totals 28 bytes (20 bytes IPv4 + 8 bytes UDP) or 48 bytes for IPv6. Ensure that underlying physical links support MTUs of 1500–1600 bytes or enforce TCP MSS clamping at the tunnel ingress:
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu - Key Rollover Overlap Window: Configure routing daemons (such as FRR or BIRD) to maintain overlapping validity for both current and next keys for at least 60 seconds during key rotation events.
- Socket Receive Buffer Optimization: Prevent artificial window clamping caused by kernel memory constraints by adjusting memory limits in
/etc/sysctl.conf:net.ipv4.tcp_rmem = 4096 87380 33554432 net.ipv4.tcp_wmem = 4096 65536 33554432 net.core.rmem_max = 33554432
Validating Socket Stability
Verify socket performance by querying kernel diagnostic telemetry with ss -tiepm state syn-recv. Confirm that tcpi_retrans_synack remains at zero and that TCP-AO authenticated sessions stay robust across FoU links.