Once DNS has produced an IP address, a packet still passes two gates that decide whether it arrives and how much it can carry: the routing table picks an exit by longest prefix match, and the link caps a single packet by its MTU.
Neither needs attention day to day, until a particularly awkward class of failure appears: small requests work perfectly and slightly larger responses hang, with nothing unusual in the logs at either end. That is almost always MTU, and it is hard to diagnose because something along the path is dropping the ICMP messages used to negotiate it — so the negotiation fails silently. This article works from CIDR prefixes and matching rules through the data structure the kernel uses for that match, how path MTU is discovered, where discovery breaks, and why encapsulation (VPNs, tunnels, overlays) makes the problem common.
1. The Mathematics and Data Structures of LPM
Classless Inter-Domain Routing (CIDR) eliminates fixed class boundaries. A router evaluating a destination IP must find the most specific subnet match among millions of BGP routes. Doing this via linear iteration is computationally impossible at line rate.
Modern Linux kernels use an LC-Trie (Level-Compressed Trie) for the IPv4 routing table. Unlike a standard binary trie which requires \(O(W)\) lookups where \(W\) is the IP address length (32 for IPv4), an LC-trie compresses sparse branches and path nodes.
The mathematical representation of path compression in an LC-Trie assumes that for a given node \(v\) with a branching factor \(k\), the search time is reduced. If \( n \) is the number of routes, the expected depth of an LC-trie is bounded by \( O(\log n) \). The kernel represents routing tables as compressed arrays, pulling entire tree nodes into a single L1/L2 CPU cache line.
/* Excerpt from linux/net/ipv4/fib_trie.c */
struct key_vector {
t_key key;
unsigned char pos; /* 2log(KEYLENGTH) bits needed */
unsigned char bits; /* 2log(KEYLENGTH) bits needed */
unsigned char slen;
union {
/* This array's size is 2^bits */
struct key_vector __rcu *tnode[0];
struct fib_alias __rcu *leaf;
};
};
The fib_lookup function traverses this structure. Because of Read-Copy-Update (RCU) synchronization, the data plane can perform lookups entirely lock-free, preventing multi-core contention on the routing table.
Destination IP: 10.22.18.7 (00001010.00010110.00010010.00000111)
LC-Trie Traversal:
- Check root node, shift to branch based on `pos` and `bits`.
- Match against `10.22.16.0/20` (Winner: Specific Service Subnet)
- Exceeds `10.0.0.0/8` precision.

Visualizing Route Selection with eBPF/XDP
In high-performance architectures (e.g., Cloudflare, Meta), packets never reach the standard IP stack. Instead, eBPF (Extended Berkeley Packet Filter) hooks at the XDP (eXpress Data Path) layer, querying the FIB directly from the NIC driver.
flowchart TD
A[NIC Rx Ring
Dest: 10.22.18.7] --> B{XDP Hook
eBPF Program}
B -->|bpf_fib_lookup| C((Kernel FIB
LC-Trie))
C -.->|Match 10.22.16.0/20| B
B --> D{MTU Check}
D -->|<= MTU| E[XDP_REDIRECT
Zero-Copy Forward]
D -->|> MTU| F[XDP_PASS
Pushed to generic Skb stack]
F --> G[ip_local_deliver / ip_forward]
2. MTU, MSS, and the Mathematics of Encapsulation
Routing determines the egress interface, which imposes a Maximum Transmission Unit (MTU). Standard Ethernet enforces a 1500-byte MTU. For TCP payloads, we must compute the Maximum Segment Size (MSS).
The equation for calculating MSS in heavily encapsulated data center environments (e.g., VXLAN overlays over IPsec) is:
$$ MSS = MTU_{phys} – H_{eth} – H_{ipsec} – H_{vxlan} – H_{outer\_ip} – H_{inner\_ip} – H_{tcp} $$
For standard IPsec over IPv4 with AES-GCM:
Base MTU: 1500 bytes
IPv4 Header: 20 bytes
ESP Header + IV + Trailer + ICV: ~40 bytes
Outer IPv4 Header: 20 bytes
TCP Header: 20 bytes
Effective MSS = 1500 - 20 - 40 - 20 - 20 = 1400 Bytes
Relying on the IP layer for fragmentation is a critical anti-pattern. IP fragmentation relies on the ip_fragment() kernel function, which allocates new sk_buff structures, copies payload fragments, and consumes massive CPU cycles. At 10Gbps+, IP fragmentation will immediately saturate kernel softirq (ksoftirqd), leading to packet drops. Transport layer segmentation (via TCP MSS clamping or TSO/GSO offloading) is mandatory for line-rate speeds.
3. Kernel-Level Debugging: `perf` and PMTUD
Path MTU Discovery (PMTUD) relies on ICMP Fragmentation Needed. However, when intermediate firewalls drop ICMP (a PMTU Blackhole), the sender’s TCP stack never receives the signal to shrink the MSS.
We can trace MTU failures and routing drops directly using perf and ftrace.
# Trace ICMP Need Frag reception in the kernel
sudo perf record -e icmp:icmp_unreach -a -g
# Trace TCP MTU probing (RFC 4821) when PMTUD fails
sudo perf probe -a tcp_mtu_probing
sudo perf record -e probe:tcp_mtu_probing -aR
# Investigate XDP redirects and FIB lookup failures
sudo bpftrace -e 'kprobe:bpf_fib_lookup { @[kstack] = count(); }'
In the Linux kernel, when a PMTU blackhole is detected, RFC 4821 Packetization Layer Path MTU Discovery (PLPMTUD) can dynamically adjust the MSS without relying on ICMP. This is enabled via sysctl net.ipv4.tcp_mtu_probing=1.
/* Excerpt from net/ipv4/tcp_timer.c handling PMTU probes */
static void tcp_mtu_probing(struct inet_connection_sock *icsk, struct sock *sk)
{
struct tcp_sock *tp = tcp_sk(sk);
/* Probe for larger MTU, or drop MSS if blackhole detected */
if (tcp_mtu_probe(sk)) {
tcp_sync_mss(sk, icsk->icsk_pmtu_cookie);
}
}
4. Production Architecture Post-Mortem
The eBPF / XDP Routing Bypass
During the design of a multi-terabit Edge CDN, traditional Linux IP forwarding (via
ip_forward) bottlenecked at ~2Mpps per core due tosk_buffallocation overhead. We architected an XDP-based fast path. The eBPF program hooks directly into the NIC’s receive ring buffer, reads the destination IP, callsbpf_fib_lookup(), updates the MAC addresses, and issuesXDP_REDIRECTto send the packet out the egress interface without ever allocating ansk_buffor triggering a kernel interrupt. This pushed throughput to 14Mpps per core.However, we hit an MTU trap. XDP programs process raw frames. If a payload exceeded the egress MTU,
XDP_REDIRECTwould silently drop the frame. We had to implement custom eBPF logic to parse the MTU from the FIB lookup result, manually craft anICMP Packet Too Bigframe in eBPF, and reflect it back to the sender viaXDP_TXto ensure PMTUD worked flawlessly.
5. Automated Data-Plane Validation
Modern networking relies on programmatic verification. Below is a Python script using pyroute2 to directly query the Linux Netlink socket for FIB routing decisions and PMTU metrics, bypassing standard shell commands.
from pyroute2 import IPRoute
import math
ipr = IPRoute()
destination = "10.22.18.7"
# Query Netlink socket for exact kernel routing decision
route = ipr.route('get', dst=destination)[0]
attrs = dict(route['attrs'])
egress_iface = attrs.get('RTA_OIF')
gateway = attrs.get('RTA_GATEWAY', 'Direct Connect')
mtu = attrs.get('RTA_METRICS', {}).get('RTAX_MTU', 1500)
print(f"Destination: {destination}")
print(f"Egress Interface Index: {egress_iface}")
print(f"Gateway: {gateway}")
print(f"Path MTU: {mtu} bytes")
# Hardware Segmentation Math (TSO)
ip_tcp_headers = 40
payload_size = 65535 # Max GSO Super-frame
segments = math.ceil(payload_size / (mtu - ip_tcp_headers))
print(f"NIC TSO will slice super-frame into {segments} hardware segments.")
Simulation profiles of zero-copy routing latency and MTU penalty drops can be found in cidr-mtu-results.csv.
6. Animated Walkthrough
7. Engineering Heuristics & Anti-Patterns
- Overusing Host Routes: Injecting millions of
/32host routes destroys LC-Trie efficiency and evicts L2/L3 CPU caches, causing massive lookup latency. Aggregate where possible. - Disabling ICMP Globally: Blocking
ICMP Type 3 Code 4breaks PMTUD, resulting in silent blackholes on overlay networks. Always allow PMTU ICMP packets through security groups. - Ignoring Jumbo Frames: In backend storage networks (e.g., Ceph, iSCSI), leaving MTU at 1500 bytes causes immense TCP header overhead and interrupts. Enable Jumbo Frames (9000 bytes) to dramatically boost Gbps throughput.
- Misunderstanding TSO/GSO: Tools like
tcpdumpmight show 65KB TCP packets exiting your server. This is not an MTU violation; it is TCP Segmentation Offload (TSO) passing a massive super-frame to the NIC hardware, which slices it into MTU-compliant packets at the physical layer.
8. Routing and MTU Evidence Matrix
When debugging routing or MTU failures, “works” and “does not work” are not enough. The matrix below ties each conclusion to reproducible evidence: route selection, next hop, egress MTU, ICMP reachability, and hardware offload state. This helps separate longest-prefix matching from PMTUD blackholes, overlay encapsulation, and packet-capture artifacts.
| Symptom | Layer to inspect first | Evidence to preserve | Decision boundary |
|---|---|---|---|
| Destination leaves through the wrong interface | FIB/LPM | ip route get, Netlink result, matched prefix, and next hop. |
Confirm whether a longer prefix overrides the default route instead of blaming DNS. |
| Small packets work but large transfers time out | Path MTU | DF ping, tracepath, ICMP Packet Too Big, and interface MTU. |
If ICMP is blocked, check PLPMTUD and MSS fallback behavior. |
| Overlay tunnel stalls intermittently | Encapsulation overhead | GRE/IPsec/WireGuard header overhead, effective MSS, and retransmission events. | Encapsulation reduces payload space; the physical NIC MTU is not the whole story. |
| Packet capture shows 65KB packets | TSO/GSO offload | ethtool -k, capture point, offload flags, and actual wire frames. |
A pre-NIC super-frame does not mean the wire violated MTU. |
FAQ
Why doesn’t the kernel just use a Hash Table for routing?
Hash tables map exact keys to values \(O(1)\), but IP routing requires Longest Prefix Match, where the destination address is not known to precisely match a specific prefix length. Tries naturally support hierarchical prefix matching. Hash tables are only used for exact-match flow caching (like the Conntrack table).
How does MTU affect BGP?
BGP runs over TCP. If your BGP routers establish peering over an IPsec tunnel or GRE with a mismatched MTU, the BGP OPEN messages (which are small) will succeed, but the subsequent BGP UPDATE messages carrying full routing tables will exceed the MTU and drop, causing BGP sessions to constantly flap.
References
- Linux Kernel IP Sysctl Documentation
- RFC 4821: Packetization Layer Path MTU Discovery
- Cilium: eBPF XDP Routing Architecture
With routing hardware offloads and MTU mechanics exposed, our next article explores how the TCP state machine reacts mathematically to the congestion signals these networks generate.