Runbook: Investigate an MTU Issue
1 · Prerequisites
Confirm every item is in place before any state change.
- MTU and fragmentation — the constraint every tunnel violates
- MTU basics — 1500 default, jumbo 9000, 802.1Q tag 4 bytes, IPv6 minimum 1280
- Tunnel overhead — WireGuard 32-80, IPsec 50-66, GRE 24, VXLAN 50
- PMTUD — RFC 1191, RFC 8201, ICMP Frag Needed, black hole detection, MTU 1280 floor
- MSS clamping — ip adjust-mss, MSS = MTU - 40, clamp-mss-to-pmtu, and which interface to clamp on
- MTU and fragmentation troubleshoot — ping -M do -s, tracepath, ICMP filtering
- MTU validation — end-to-end verification, jumbo on all path, sub-interface alignment
2 · Pre-checks
Read-only diagnostic commands. If any of these don't match expected output, stop and investigate further.
- · The symptom has been restated as a size rather than an adjective. "Large packets fail" is not evidence; "the TLS handshake completes and the first response body stalls, every time, on the same file" is a starting point and a sized ping turns it into a number
- · A default-size ping to the destination succeeds. If it does not, this is not an MTU incident: the path is down and the entry point is a routing runbook, not this one
- · The path is named end to end - which source, which destination, and every tunnel, VLAN and provider hand-off in between. MTU is a property of a path, not of an interface, and a runbook run against the wrong path produces a confident wrong answer
- · The interface MTU of every interface on the path this router owns is on file:
show interfaces, andshow interfaces wireguard/show interfaces vti/show interfaces tunnelfor any tunnel in the path - · Whether anything changed has been established:
show system commitfor the revision list, andshow system commit diff Nfor what a given revision actually altered. A path MTU that was fine last week and is not today usually has a commit or a provider change behind it - · Out-of-band access is confirmed before any remediation. An interface MTU change bounces the link; if that link carries your session, you will not see whether the change worked
- · Both address families are in scope. IPv4 and IPv6 do not share a path MTU, do not share an MSS, and do not share a firewall rule set. Testing one and fixing one is half a fix
3 · Procedure
Execute each step in order. Verify the expected output of a step before moving to the next.
- 1Confirm the path works at all: a default-size ping to the destination. This runbook only applies where small packets succeed and large ones do not.
- 2Convert the symptom into a number. Run a sized, do-not-fragment ping and bisect:
ping DEST size 1472 do-not-fragment count 3, then halve the gap until you have the largest payload that succeeds. The IP packet is the payload plus 28 bytes, so payload 1472 is a 1500-byte packet. - 3Run the same size again WITHOUT do-not-fragment. This second ping is what distinguishes the four outcomes, and it is the step operators skip.
- 4Classify: large DF succeeds (not an MTU fault); large DF returns an ICMP fragmentation-needed with an MTU value (PMTUD is working, the path MTU is now known); large DF hangs but the non-DF ping succeeds (PMTUD black hole, ICMP is being filtered); both hang (the path is broken at that size for another reason).
- 5Try to locate the constraining hop, and treat the number from step 2 as the answer if you cannot. VyOS ships
tracerouteandmtr, neither of which reports per-hop MTU; where PMTUD is working, the ICMP fragmentation-needed carries the next-hop MTU and a capture is what reads it. - 6Decide ownership: is the constraining hop an interface this estate configures, or is it inside a provider or partner network? This single question selects the fix and cannot be skipped.
- 7If PMTUD is black-holed, check whether this router is the one filtering:
show firewall ipv4 input filter,show firewall ipv4 forward filterand their IPv6 equivalents, reading the per-rule counters rather than the intent. ICMP fragmentation-needed and ICMPv6 packet-too-big must be permitted. - 8Compute the target values before changing anything: inner MTU is wire MTU minus tunnel overhead; IPv4 MSS is MTU minus 40; IPv6 MSS is MTU minus 60. Write both numbers into the incident record so the reviewer can check the arithmetic.
- 9Choose one fix and name what it costs: permit the ICMP that PMTUD needs (restores the mechanism, only works where you own the filter); correct the interface MTU (right when a tunnel MTU is simply wrong, and it bounces the link); clamp MSS (cheapest, works through a filtering provider, and does nothing for UDP).
- 10Apply it with a net:
compare, thencommit-confirm 5, then leave configure mode and re-run the sized ping from the operational shell before youconfirm. An MTU change on the interface carrying your session is the one that needs the timer most. - 11Verify on traffic, not on configuration. Re-run the sized do-not-fragment ping at the new ceiling, confirm the clamped MSS on the wire with a SYN capture, and then confirm the ORIGINAL application symptom is gone. A ping that now passes is necessary and not sufficient.
- 12Run
save, then record the measured path MTU, the constraining hop, the fix and its owner in the MTU inventory. A path MTU that was measured and not written down will be measured again by the next person under the same pressure.
4 · Verification
Confirm the procedure actually fixed the problem.
- ✓A sized do-not-fragment ping at the new working size succeeds three times out of three, in both directions of the path where a host at each end is available
- ✓The sized do-not-fragment ping now succeeds at the value the fix targeted, re-measured by the same bisection that produced the original number. This is the verification, not a hop-by-hop report - VyOS has no op-mode command that prints per-hop MTU
- ✓Where MSS clamping was applied: a SYN capture on the interface the clamp is bound to shows the clamped value, not 1460 -
monitor traffic interface eth0 filter "tcp[tcpflags] & tcp-syn != 0" - ✓Where a firewall rule was added for ICMP: the rule counter is non-zero under real traffic. A rule at zero packets has not been proved to be the rule in effect
- ✓The application symptom that produced the page is gone, tested against the same operation that failed - the large upload, the file copy, the backup job - and not against ping alone
- ✓IPv6 was tested separately from IPv4 - the same
ping ADDR size N do-not-fragment count 3bisection against an IPv6 destination - and either fixed or explicitly recorded as out of scope - ✓
comparefromconfigureproduces no output, andconfigure,load /config/config.boot,compare,discardproduces no diff: the fix is saved, not only live - ✓The measured path MTU, the constraining hop and the chosen fix are in the MTU inventory with a date
5 · Rollback
If verification fails, undo the procedure in reverse order.
- ↶Interface MTU change:
setthe node back to its previous value (ordeleteit to return to the interface default),compare,commit-confirm 5, thenconfirm. Restoring the MTU bounces the link a second time, so it is a change with the same blast radius as the original - ↶MSS clamp:
delete interfaces ethernet ethN ip adjust-mss(and theipv6 adjust-mssnode separately), thencommit. Existing TCP connections keep the MSS they negotiated at SYN time and will not revert until they are re-established - ↶Firewall rule for ICMP:
deletethe rule number you added andcommit. Removing an accept rule from a default-deny chain is a security-relevant change, so it needs the same review as adding one - ↶Do NOT reach for
rollback Nas the undo. VyOS documents it as applying the revision and triggering a system reboot, which on a router carrying traffic is an outage rather than a revert. Usecompare Nto READ what a revision changed, and undo the specific nodes yourself - ↶If the router became unreachable at the moment of the commit, do nothing and let the
commit-confirmtimer expire. A second blind attempt from a different host usually makes the evidence worse - ↶POINT OF NO RETURN: lowering an MTU or clamping an MSS does not reverse the transfers that already failed. Anything that timed out during the incident - a backup, a replication job, a batch upload - has to be re-driven by whoever owns it
- ↶POINT OF NO RETURN: an MTU raised on a link whose far end has not been raised too. The link comes up, small packets pass, and large ones are dropped silently by the far end. Rolling back this router restores service; it does not tell you the far end was the problem
6 · Escalation
When the runbook isn't enough, contact:
- · Escalate to the provider or partner NOC when the constraining hop is outside the estate. Ask two specific questions - what is the MTU on that hop, and do you filter ICMP fragmentation-needed - because "our network is fine" answers neither
- · Escalate to network engineering before changing the MTU on any link that is one half of a redundant pair. Lowering the MTU on one path and not the other converts a size problem into a failover problem
- · Escalate to security before permitting ICMP through a default-deny chain, even for fragmentation-needed. Widening an inbound filter is a security decision with an availability justification, which is not the same as an availability decision
- · Escalate to the application owner rather than clamping harder when the failing traffic is UDP - QUIC, a UDP-based VPN, NFS over UDP, media. MSS clamping is a TCP mechanism and will not touch it
- · Escalate to the platform team if the interface will not accept the MTU you calculated, or comes back down after the change. That is a driver or hardware conversation, not a configuration one
- · Escalate rather than guess if the path crosses a tunnel this team does not own. Changing the inner MTU on one end of a tunnel whose far end you cannot see produces an asymmetric MTU, which is harder to diagnose than what you started with
An MTU incident almost never arrives described as one. It arrives as four reports that read like four different problems:
- The VPN is up, but the file share on the other side is unusable.
- The site loads, and the login page hangs forever.
- SSH is fine; copying anything large stalls at the same point every time.
- The nightly replication to the DR site started failing on Tuesday, and nobody changed anything.
They are one fault. Something on the path cannot carry a packet above a certain size, and everything below that size works perfectly — which is precisely why none of the four reports mentions size, and why the first hour of these incidents is usually spent on DNS, on the application, and on the firewall.
The whole job of this runbook is to convert an adjective into a number in the first ten minutes. “Large packets fail” is not evidence. “1372 bytes of payload succeeds and 1373 does not” is evidence, and it is most of the diagnosis.
When to use this runbook
Small packets reach the destination and large ones do not, on a path that this estate has a router on. The classic tells are a protocol that completes its handshake and then stalls on the first substantial payload, and a failure that reproduces at exactly the same size every time.
When not to use it
- A default-size ping already fails. Nothing here applies; the path is broken
and the entry point is
vyos-rb-troubleshoot-missing-route. - Loss is proportional at every size, or comes and goes. That is
vyos-rb-investigate-packet-loss— MTU faults are a cliff, not a slope. - The tunnel is new and has never carried a large packet. Sizing the tunnel is
part of turn-up:
vyos-rb-configure-wireguardandvyos-rb-configure-ipsecboth end with a sized ping for this reason.
Blast radius
Every step up to the fix is read-only and can be run during business hours from any session. The fix is not. An interface MTU change bounces the link, an MSS clamp changes every TCP connection that later crosses the interface, and permitting ICMP widens a filter. Treat the remediation as a change with its own review, on a path that has just proved it can surprise you.
Step 1: turn the adjective into a number
ping 192.0.2.50 count 3
ping 192.0.2.50 size 1472 do-not-fragment count 3
ping 192.0.2.50 size 1372 do-not-fragment count 3
ping 192.0.2.50 size 1422 do-not-fragment count 3size is the ICMP payload, not the packet. The IP packet is the payload plus
28 bytes — 20 of IP header and 8 of ICMP echo header — so payload 1472 is a
1500-byte packet and payload 1372 is a 1400-byte packet. Subtract 28 from the
MTU you are testing for; this is the arithmetic operators most often get
wrong, and getting it wrong shifts every conclusion by 28 bytes.
Four or five probes bisect the whole range. Start at 1472, and when it fails, halve the gap rather than stepping down by ten — a linear walk from 1472 is forty probes and an hour you do not have.
If you prefer the underlying tool, ping -M do -s 1472 192.0.2.50 is the same
test; the course’s Part LI lessons use that form throughout.
Step 2: run the same size again without the DF bit
This is the step that gets skipped, and it is the step that tells you what kind of MTU fault you have.
ping 192.0.2.50 size 1472 count 3Two probes at one size produce four outcomes, and each one points at a different fix:
| DF probe | Non-DF probe | What you have | Where to go |
|---|---|---|---|
| Succeeds | Succeeds | Path MTU is at or above the size you tested | Not an MTU fault. Look at the application |
| Returns ICMP fragmentation-needed with an MTU value | Succeeds | PMTUD is working and has told you the answer | Step 3, then decide whether anything needs changing at all |
| Hangs, no ICMP at all | Succeeds | PMTUD black hole: something drops the big packet and sends nothing back | Step 3, then Step 4 — the fix is ICMP or MSS |
| Hangs | Hangs | The path cannot carry that size in any form | Not primarily MTU. Routing, filtering, or a hop that drops fragments |
The second row is the benign case and it is worth pausing on. If the path returns an ICMP fragmentation-needed carrying a usable MTU, the mechanism is working: senders that respect Path MTU Discovery will size themselves correctly on their own. If an application is still failing, the application is not honouring PMTUD, and clamping MSS is a workaround for that application rather than a repair of the network.
The third row is the one that generates incidents. Nothing is broken visibly; a router or firewall somewhere silently discards the oversized packet without generating the ICMP that would have told the sender why.
Step 3: find the hop, or accept that you cannot
Where PMTUD is working — the second row of the Step 2 table — the path has already told you the number and the hop that owns it. The ICMP fragmentation-needed carries the next-hop MTU, and a capture is what reads it:
monitor traffic interface eth0 filter 'icmp or icmp6'IP 198.51.100.9 > 198.51.100.1: ICMP 192.0.2.50 unreachable -
need to frag (mtu 1450), length 556Illustrative output
Two things come out of one line: the constraining MTU (1450) and the address
of the hop that announced it (198.51.100.9). That is the part of a
tracepath report you were actually going to act on — the binding constraint
and its owner — read from the router you are already logged into. What it
will not give you is the MTU of hops that are not currently the constraint,
which is a real limitation only if you intend to raise the ceiling twice.
If nothing arrives, that is the black-hole case and it is a finding, not a
failed test. Run traceroute to establish the topology — the hops, and where
the path leaves your estate — and pair it with the measured number from Step
- Knowing “1372 fits, 1373 does not, and hop 4 is the provider’s” is enough to choose a fix and enough to open a ticket with.
Do IPv6 separately and expect a different answer. The two families do not share a path MTU, they do not share an MSS, and they do not share a firewall rule set. A fix applied to one leaves the other exactly as it was.
Step 4: is the constraining hop yours?
Everything after this depends on the answer, so answer it explicitly and write it into the incident record.
The hop is an interface this estate configures — a tunnel, a VLAN sub-interface, a link you own both ends of. The MTU is probably simply wrong, and correcting it is the honest fix. Check the arithmetic below before you change it.
The hop is inside a provider or partner network. You are not going to change it. Your options are to size your own traffic to fit, or to get the provider to stop filtering the ICMP that would let PMTUD do it for you. Both are legitimate; only one is under your control today.
The hop cannot be identified at all because the path goes dark partway. Then the measured number from Step 1 is still valid and still actionable — you know what fits, even if you do not know why. Clamp to what fits, record that the constraining hop is unknown, and open the provider ticket anyway.
If PMTUD is black-holed, check that this router is not the one doing the filtering before blaming anyone else:
show firewall ipv4 input filter
show firewall ipv4 forward filter
show firewall ipv6 input filter
show firewall ipv6 forward filter
show firewall statisticsA default-deny chain with no rule permitting ICMP fragmentation-needed (IPv4) or ICMPv6 packet-too-big is a PMTUD black hole that this team owns. Read the counters: an accept rule sitting at zero packets while the default-action counter climbs means your traffic is being matched by something other than the rule you believe is in effect.
The arithmetic, before you change anything
| Path element | Overhead, IPv4 outer | Inner MTU from 1500 | IPv4 MSS | IPv6 MSS |
|---|---|---|---|---|
| Plain Ethernet | — | 1500 | 1460 | 1440 |
| 802.1Q VLAN tag | 0 at layer 3 | 1500 | 1460 | 1440 |
| GRE | 24 | 1476 | 1436 | 1416 |
| WireGuard | 32 | 1468 | 1428 | 1408 |
| WireGuard, IPv6 outer | 80 | 1420 | 1380 | 1360 |
| VXLAN | 50 | 1450 | 1410 | 1390 |
| IPsec ESP over a VTI | 38–66, cipher dependent | measure it — and the interface defaults to 1500 | measure it | measure it |
MSS is the TCP payload only: it excludes both the TCP header and the IP header. So IPv4 MSS is MTU minus 40, and IPv6 MSS is MTU minus 60. The twenty-byte difference between the families is the single most common arithmetic error in this whole subject, and its symptom is an IPv6 path that still stalls after “the MTU was fixed”.
IPsec is deliberately left as “measure it”. The overhead depends on the
cipher, on whether NAT traversal has added its eight bytes of UDP
encapsulation, and on the length of the integrity check value, which is why
Part LI-02 lands on a conservative VTI MTU of 1438 rather than a computed
one. Read the negotiated proposal out of the Proposal column of
show vpn ipsec sa — that is the cipher actually in use, which is not
necessarily the one at the top of your proposal list — and then measure.
The second half of that row matters as much as the arithmetic. A VTI comes
up at MTU 1500. Nothing about set interfaces vti vti0 sizes it for the
overhead the tunnel is about to add, so an IPsec tunnel that was built
without an explicit mtu is not “probably fine” — it is the exact
configuration this runbook exists to diagnose, and it will present as an
application fault. Confirm it with show interfaces vti vti0 before
theorising about the path beyond it.
Step 5: choose the fix, and say what it costs
Permit the ICMP that PMTUD needs. This repairs the mechanism rather than working around it, and it fixes every protocol at once rather than only TCP. It only works where you own the filter, and it widens an inbound chain, so it is a security-reviewed change.
set firewall ipv4 name WAN-IN rule 5 action accept
set firewall ipv4 name WAN-IN rule 5 protocol icmp
set firewall ipv4 name WAN-IN rule 5 icmp type 3
set firewall ipv4 name WAN-IN rule 5 icmp code 4
set firewall ipv6 name WAN6-IN rule 5 action accept
set firewall ipv6 name WAN6-IN rule 5 protocol icmpv6
set firewall ipv6 name WAN6-IN rule 5 icmpv6 type-name packet-too-big
compare
commit-confirm 5Correct the interface MTU. The right fix when a tunnel or a link is simply configured wrong. It bounces the link — briefly for an Ethernet interface, and long enough to notice — and it is only correct if the far end agrees.
Clamp MSS. The cheapest fix and the one that works through a provider you cannot change, because it needs nothing from anybody else. It is TCP-only.
set interfaces wireguard wg01 ip adjust-mss clamp-mss-to-pmtu
set interfaces wireguard wg01 ipv6 adjust-mss clamp-mss-to-pmtu
compare
commit-confirm 5clamp-mss-to-pmtu derives the value from the interface MTU, which is why
setting the interface MTU deliberately matters even when the clamp is doing
the work. VyOS documents the derivation precisely: the MSS becomes the
interface MTU minus 40 for IPv4 — 20 bytes of IP header and 20 of TCP — so an
interface at 1468 advertises 1428. Where the underlay is itself constrained —
PPPoE, a tunnel inside a tunnel — ip adjust-mss <value> takes an explicit
number from your Step 1 measurement, which is safer than a derived one that
is derived from the wrong MTU.
Note that ip adjust-mss and ipv6 adjust-mss are separate nodes on the
same interface. Setting one does nothing for the other, which is the
mechanical reason behind “fixed for IPv4, still broken for IPv6” appearing
twice in this runbook.
Hold. A first-class option. If the path is degraded rather than down, and the change window is hours away, holding with a named owner and an end time is better than a rushed MTU change on a live provider link. Write the owner and the time into the incident record, not into somebody’s memory.
Step 6: apply it with a net, then verify on traffic
compare
commit-confirm 5
exit
ping 192.0.2.50 size 1372 do-not-fragment count 3Leave configure mode and test from the operational shell while the timer runs.
If the result is right, go back in and confirm, then save. If it is not,
do nothing and let the timer restore the previous state — the operator who has
just been wrong once is not the best judge of the second attempt.
monitor traffic interface eth0 filter 'tcp[tcpflags] & tcp-syn != 0'monitor traffic is VyOS’s wrapper around tcpdump, so the filter syntax is
tcpdump’s and the output is tcpdump’s; Ctrl-C stops it. The SYN carries the
MSS option, and this capture is the only direct evidence that the clamp is on
the interface the SYNs actually cross. A clamp bound to the wrong interface
commits cleanly, validates cleanly, and does nothing.
The interface to watch is the one the SYN crosses, which is not always the one you clamped. On a tunnel the SYN enters on the LAN side and leaves on the tunnel; the clamp rewrites it on egress, so capture on the tunnel interface to see the clamped value and on the LAN interface to see what it was before.
Then verify the thing that was actually broken. Re-run the failed upload, the file copy, the backup job. A sized ping that now passes is necessary and not sufficient, and the gap between the two is where “we fixed it” turns into a second page an hour later.
Common patterns
| Symptom | Likely cause | Where to look |
|---|---|---|
| Handshake completes, first large response hangs | Path MTU below what the sender is using | Sized do-not-fragment ping, bisected |
| DF ping hangs, non-DF ping succeeds | PMTUD black hole — ICMP filtered somewhere | Own firewall counters first, then the provider |
| Fixed for IPv4, still broken for IPv6 | Separate path MTU, separate MSS, separate filter | The same sized-ping bisection to an IPv6 destination, ipv6 adjust-mss, and the IPv6 rule set |
| Clamp committed, nothing changed | Wrong interface, or existing connections | SYN capture on the interface the SYNs cross |
| Works one direction, fails the other | Asymmetric tunnel MTU — the two ends disagree | show interfaces on both ends of the tunnel |
| Failing traffic is unaffected by the clamp | The traffic is UDP | Protocol of the failing flow, before tuning further |
| Path MTU reported below 1280 for IPv6 | Below the IPv6 minimum link MTU | The link itself — this is not a tuning problem |
| Everything passes now, breaks after a reboot | Committed and never saved | /config/config.boot |
Escalation
Escalate when:
- The constraining hop is outside the estate.
- The link is one half of a redundant pair.
- The fix requires widening a default-deny chain.
- The failing traffic is UDP and the clamp cannot reach it.
- The interface refuses the MTU, or does not come back after the change.
- The path crosses a tunnel whose far end this team cannot see.
References
- VyOS documentation - Ethernet interfaces (mtu, ip adjust-mss)
- VyOS documentation - IPv4 firewall
- VyOS documentation - WireGuard interfaces
- VyOS documentation - VTI interfaces (the IPsec tunnel interface and its default MTU)
- VyOS documentation - connectivity tests (ping size / do-not-fragment, traceroute, mtr)
- Linux man page - ping(8)
- Linux man page - tracepath(8) - the per-hop MTU tool VyOS does not ship
- RFC 1191 - Path MTU Discovery
- RFC 8201 - Path MTU Discovery for IPv6
- RFC 4821 - Packetization Layer Path MTU Discovery