Repository navigation
ipv6tunneling: carry packets of up to 1280 bytes through a tunnel with a smaller mtu - #1292
adamgeorge309 wants to merge 1 commit into
Conversation
An Ipv6TunnelInterface whose mtu parameter is below 1280 bytes refused every forwarded packet larger than that value in Ipv6::fragmentAndSend() (Ipv6.cc:1059-1073). It sent an ICMPv6 (Internet Control Message Protocol for Internet Protocol version 6) Packet Too Big that reported the tunnel mtu, for example 1200, because Ipv6Tunnel::configureNetworkInterface() (Ipv6Tunnel.cc:35) copied the parameter into the interface MTU (maximum transmission unit) unchanged. RFC (Request for Comments) 8201 (Path MTU Discovery for IPv6) Section 4 does not let a source lower its path MTU below 1280 bytes, so packets between the mtu parameter and 1280 bytes never got through. RFC 2473 (Generic Packet Tunneling in IPv6) Section 7.1 separates two cases for an original packet that exceeds the tunnel MTU. One larger than the IPv6 minimum link MTU of 1280 bytes is refused with a Packet Too Big that reports max(tunnel MTU, 1280). One of 1280 bytes or less is encapsulated, and the tunnel packet is fragmented. The interface MTU is now max(mtu, 1280), which gives both cases. A node that sends its own packets into such a tunnel fragmented them to the tunnel mtu, and now fragments them to 1280 bytes. A tunnel MTU below 1280 bytes is a valid state in RFC 2473, which derives it from the path MTU to the exit point (Section 6.7), so the value is accepted, not rejected. Ipv6 originates the tunnel packet and fragments it to the MTU of its outgoing interface, not to mtu plus the 40-byte tunnel header: Ipv6 has no way for a sender to ask for a smaller fragment size, and adding one would change a contract between the modules. So if a link inside the tunnel is smaller than the outgoing interface, a tunnel packet that carries a packet of 1280 bytes or less is still lost there. The tunnels that Mobile IPv6 and Proxy Mobile IPv6 create keep the default mtu of 1500 bytes and do not change. tests/module/IPv6_tunnel_mtu_below_minimum.test reproduces it: a router tunnels 1248-byte packets into a tunnel with an mtu of 1200 bytes. Before this commit hostB receives 0 of 4 packets and hostA receives four Packet Too Big messages; after it, hostB receives 4 of 4. Change: src.networklayer.ipv6tunneling | behavior.change.fix | test whatsnew
| // fragmented. So the interface accepts packets of up to that size. Ipv6 | ||
| // originates the tunnel packet and fragments it to the MTU of its outgoing | ||
| // interface. | ||
| networkInterface->setMtu(std::max(par("mtu").intValue(), (intval_t)IPv6_MIN_MTU)); |
There was a problem hiding this comment.
🔴 Transit links drop admitted tunnel packets
With mtu below 1280 and a smaller transit link, the tunnel admits inner packets that its outer packet cannot carry. fragmentAndSend uses the entry's outgoing MTU, so a 1280-byte transit link drops a 1320-byte packet sent over a 1500-byte entry link.
Learn more
The tunnel interface MTU controls the size of the inner packet accepted for encapsulation. The tunnel's configured MTU represents the path toward its exit, but handleUpperPacket only submits the inner packet to IPv6. fragmentAndSend fragments the resulting outer packet only when it exceeds the outgoing interface MTU. Thus admitting an inner packet does not guarantee that the outer packet fits later links. A transit router cannot fragment that forwarded outer packet, and it sends Packet Too Big instead.
Example: Configure tunnel mtu = 1200B, an entry link with MTU 1500B, and a transit link with MTU 1280B. An inner 1280-byte packet becomes a 1320-byte outer packet. The entry sends it unfragmented; the transit router rejects it, rather than delivering the original packet through the tunnel.
Recommended fix: Arrange for the tunnel entry to fragment the outer packet to the tunnel path's usable size when the inner packet is at most 1280 bytes. Preserve the 1280-byte acceptance floor for the inner packet and the Packet Too Big behavior above it. Extend the module test with a constrained downstream link and verify fragment transmission and delivery.
Was this helpful? React with 👍 or 👎 to provide feedback.
An
Ipv6TunnelInterfacewhosemtuparameter is below 1280 bytes refused every forwarded packet larger than themtuvalue with an ICMPv6 (Internet Control Message Protocol for Internet Protocol version 6) Packet Too Big that reported the tunnel mtu. RFC (Request for Comments) 2473 (Generic Packet Tunneling in IPv6) Section 7.1 (b) requires such a tunnel to encapsulate packets of up to 1280 bytes and fragment the tunnel packet, and RFC 8201 (Path MTU Discovery for IPv6) does not let a source lower its path MTU (maximum transmission unit) below 1280 bytes, so these packets never got through. The interface MTU is now max(mtu, 1280). Results change only for tunnels configured with anmtubelow 1280 bytes: there a node that sends its own packets into the tunnel now fragments them to 1280 bytes instead of to the tunnel mtu. The tunnels that Mobile IPv6 (MIPv6) and Proxy Mobile IPv6 (PMIPv6) create use the defaultmtuof 1500 bytes and do not change.Closes #1291
The problem
Ipv6Tunnel::configureNetworkInterface()(src/inet/networklayer/ipv6tunneling/Ipv6Tunnel.cc:35) set the interface MTU to themtuparameter.Ipv6::fragmentAndSend()then refused a forwarded packet above that size with a Packet Too Big that reported that size (Ipv6.cc:1059-1073).tests/module/IPv6_tunnel_mtu_below_minimum.test: hostA - borderA - transit - borderB - hostB with static routes. borderA routes hostB's prefix into anIpv6TunnelInterfacewithmtu = 1200B, and hostA sends four User Datagram Protocol (UDP) packets of 1248 bytes. On master 93210f4 hostA receives four Packet Too Big messages, each reporting 1200, and hostB receives 0 of 4 packets; on this branch hostA receives none and hostB receives 4 of 4.The fix
With the interface MTU at max(mtu, 1280), both cases of RFC 2473 Section 7.1 follow: Ipv6 accepts a packet of up to 1280 bytes into the tunnel, and the Packet Too Big for a larger packet reports at least 1280, which is case (a)'s max(tunnel MTU, 1280). Ipv6 originates the tunnel packet, so it fragments it if the tunnel packet is larger than the MTU of the outgoing interface.
A tunnel MTU below 1280 bytes is a valid state in RFC 2473: Section 6.7 derives it from the path MTU to the exit point, and Section 7.1 says what to do with it. So the value is accepted rather than rejected.
The obvious alternative, fragmenting the tunnel packet to mtu plus the 40-byte tunnel header, needs a way for
Ipv6Tunnelto askIpv6for a fragment size below the MTU of the outgoing interface.Ipv6has none (FragmentationReqcarries only the Don't Fragment bit), and adding one changes a contract between the modules, which a defect fix should not.Architectural surface
The change alters the behavior of
Ipv6TunnelInterfacefor anmtubelow 1280 bytes, and the NED (Network Description) comment of themtuparameter now states the 1280-byte floor.Ipv6Tunnel.ccnow includesnetworklayer/ipv6/Ipv6InterfaceData.hforIPv6_MIN_MTU; both directories belong to theIpv6feature, andcheck-architecture.sh src/inet/networklayer/ipv6tunnelingpasses. No parameter, packet format, C++ interface or feature descriptor changes.Verification
Release build (
make MODE=release):IPv6_tunnel_mtu_below_minimumfails on master (hostB receives 0 packets) and passes on this branch;IPv6_tunnelpasses on both.Full suites, release, on master 93210f4 and on this branch:
examples/ipv6/nclientsETHandPPPinmipv6-refactoring.csv; the errors are rows whose optional features are disabled in this build. No fingerprint moves: no shipped example, showcase, tutorial or fingerprint configuration namesIpv6TunnelInterface, and the tunnels that MIPv6 and PMIPv6 create keep the defaultmtu.tcp_*,ConvolutionalCoder12/34,EtherHost_lifecycle,ExternalProcess_3,Ieee80211BitDomain/SymbolDomain,Ieee8021d-Rstp/Stp,IPv6_packet_too_big,MIPv6_tcp_handover,PacketGate_1,UDPSocket_1).tests/protocol/ipv626 of 27 pass on both (Rfc8200OverlappingFragmentsfails on both);tests/protocol/nd22 of 37 pass on both, with the same 15 failures.make MODE=debug,inet_run_module_tests -m debug --no-build -l ERROR -f IPv6_tunnel): all pass on this branch, and the new test fails on master in debug too.doc/project/enforcement/check-commits.sh,check-classification.shandcheck-architecture.shonsrc/inet/networklayer/ipv6tunnelingandsrc/inet/networklayer/ipv6: PASS. Statistical tests andcheck-cpp.shwere not run.Not addressed here
RFC 2473 Section 7.1 (b) fragments the tunnel packet to the Path MTU to the exit point, and Section 6.7 derives the tunnel MTU from that Path MTU. The entry point fragments to the MTU of its outgoing interface instead (see The fix), and the
mtuparameter stays a fixed value. If a link inside the tunnel is smaller than the outgoing interface, a tunnel packet that carries a packet of 1280 bytes or less is still lost there.Landing order
git merge-treeagainst the heads of the open pull requests #1228, #1232, #1252 and #1256 conflicts only inWHATSNEW, where each adds an item with the same number. #1264 also conflicts in the include block ofIpv6Tunnel.cc, where both add a line at the same place; keeping both lines resolves it. The pull request that lands later renumbers itsWHATSNEWitem.