The Silent Black Hole

How an Invisible MTU Ceiling Almost Killed an Industrial IoT Deployment

The Symptom: A Network That “Mostly” Worked

Picture hundreds of sensors across remote sites publishing telemetry every second to a central broker. The data arrives—mostly.
But every few minutes, a burst of tags drops. Clients reconnect. Alarms flicker. Engineers blame the application.

The network team runs captures.
TCP retransmissions: 12–18 %. SYN storms. MQTT keepalives timing out.
No ACL denies. No route flaps. No bandwidth saturation.

It’s a black hole—packets vanish without a trace.

Why This Is Incredibly Difficult to Diagnose

MTU/MSS mismatches are the perfect crime in networking—not because they’re rare, but because they’re not an “error” in the classical sense. They’re a normal function of the network that only becomes pathological when an application refuses to tolerate TCP’s built-in resilience.

Observable SymptomCommon BlameReality
Intermittent latencyApplication bugTCP retransmitting oversized segments
ReconnectsFirmware issueKeepalive PINGREQ dropped
High CPU on brokerDDoSHandling endless retransmit storms
Tag lossSensor failureOne 1460-byte payload black-holed

It’s not broken—it’s normal.
TCP is designed to survive loss. It retransmits, shrinks windows, and backs off.
Most applications (HTTP, email, file sync) tolerate 5–15 % loss.
They just feel “slow.”

Only when you run real-time, low-latency, high-reliability protocols like MQTT in industrial IoT applications, does the normal become catastrophic.

The Culprit: A 100-Byte Invisible Toll Booth

The topology:

[Broker] → [Gateway] → [DMVPN Headend] → [Carrier MPLS] → [Spoke Router] → [Remote Gateway] → [Edge Node]

The DMVPN tunnel was configured with:

ip mtu 1400
ip tcp adjust-mss 1360

That’s ~100 bytes of overhead:

LayerOverhead
Inner IP20
Inner TCP20
GRE4
Outer IP20
IPsec ESP (AES-GCM)~36–56
Total~100–120 bytes

So the effective path MTU is ~1380–1400 bytes.

But the broker’s OS?
Local interface MTU = 1500 → advertises MSS = 1460.

The Asymmetry: A One-Way Speed Trap

DirectionSYN SourceAdvertised MSS
Broker → EdgeBroker1460
Edge → BrokerEdge (via spoke)1360

The spoke router clamps inbound SYN-ACKs to 1360 to protect the tunnel.
The headend router does not clamp outbound SYNs from the broker.

Result:
Broker sends 1460-byte payloads → + headers + tunnel overhead = ~1560 bytesdropped at headend.
No ICMP Type 3 Code 4 → black hole.

Why Most Apps Survived (But MQTT Didn’t)

TCP is resilient. It does three things when packets drop:

  1. Retransmit (fast retransmit after 3 dup ACKs)
  2. Shrink the window (congestion control)
  3. Back off (exponential RTO)

For HTTP, email, or file transfers?
→ A few retries = a 200ms delay. Users don’t notice.

For MQTT over persistent sessions?

MQTT TraitWhy It Breaks
QoS 1/2Requires PUBACK/PUBREC — one lost segment = app-level retry
KeepalivesPINGREQ/PINGRESP every 20–60s — drop = disconnect
Small, frequent messages1 drop = 10–20% of a burst
Long-lived sessionsOld MSS locked in for hours

Analogy:
Think of a highway (tunnel) with a 14-foot bridge.
Most cars (HTTP) are 12 feet tall — they slow down, wait, eventually pass.
MQTT is a convoy of 13.9-foot trucks in a tight formation.
One truck hits the bridge → the whole convoy stops, backs up, and tries again.
The highway works—but the convoy fails.

The Fix: Two Levers, One Result

1. Clamp MSS to 1300 on both default gateways

# Data center Firewall (broker side)
nat (inside,outside) source dynamic BROKER-NET interface \
    destination static REMOTE-NETS REMOTE-NETS mss 1300

# Remote Firewall/router (Edge side)
interface
 ip tcp adjust-mss 1300

Every TCP session now advertises 1300 payload
Total packet ≤ 1340 bytes → fits 1400 tunnel with headroom

2. Allow ICMP Type 3 Code 4 (PMTUD safety net)

Firewall → Access Control → Add Rule

ICMP Type 3 Code 4 → Allow (bidirectional)

→ If anything does exceed, the sender gets told:
Next-Hop MTU: 1400 → auto-adjusts

The Result

MetricBeforeAfter
TCP Retransmissions12–18 %< 0.5 %
MQTT Reconnects40–60 / hour0
Tag Loss2–5 %0 %
Latency (pub/sub)300–800 ms40–80 ms

Key Takeaways (The “Speed Limit” Lessons)

ConceptTechnical TruthHighway Analogy
MTUMax IP packet size on a linkBridge height (14 ft)
MSSMax TCP payload (MTU – 40)Truck height (13 ft)
ClampingForce-advertise lower MSSInstall a governor on every truck
PMTUDICMP 3/4 feedbackTraffic cop with a radar gun
Black HoleNo ICMP → endless retriesSpeeding ticket never delivered

Final Thought: This Is Normal TCP… Until It Isn’t

TCP was built to survive packet loss.
It assumes the network will tell it when it’s wrong.

In 99% of enterprise LANs, that assumption holds.
In tunnel-heavy, carrier-overlay IoT, it doesn’t.

The fix wasn’t a hack.
It was engineering the truth into the handshake.

Architecturally speaking, networks should not be used to force application behavior. Networks are only so fungible. The network has and sets requirements, and applications should be configured to adhere to those requirements. However, it’s wise to enforce these types of requirements in industrial IoT networks, where architecture control may be decentralized.

Also, if you run into this issue after a deployment has started or completed, resolving with the network provides the asymmetric advantage to fix completely quickly.

There is really no reason not to, for the IoT network in a situation like this, because the traffic needs conformed, regardless if the application is configured to do it or not. This is really good insurance, but it doesn’t preclude correctly configuring applications.

“The network isn’t broken. It’s just honest.”
— Every MTU debug at 2 a.m.

Share this, pass it along. Save a fellow engineer from the black hole.

Comments are closed

Latest Comments

No comments to show.