Repository navigation
ipv6: relay ICMPv6 errors about tunnel packets to the original source - #1294
adamgeorge309 wants to merge 2 commits into
Conversation
A router that forwards a User Datagram Protocol (UDP) or Transmission Control Protocol (TCP) packet into an Ipv6TunnelInterface stopped the simulation when an ICMPv6 (Internet Control Message Protocol for Internet Protocol version 6) error about the tunnel packet came back: Unknown protocol: protocolId = 69, protocolName = udp, servicePrimitive = INDICATION, pathStartGate = ...borderA.ipv6.ipv6.transportOut handleIcmpErrorIndication() pops one quoted IPv6 header and dispatches the indication by its next header. For a tunnel packet the next header is IPv6. The indication therefore came back to Ipv6 itself, which popped the inner header and dispatched it to the inner transport protocol. A router has no such module. Now the tunnel entry point reports the error to the source of the original packet. RFC (Request for Comments) 2473 (Generic Packet Tunneling in IPv6) Section 8.1 lists the problems that the entry point also reports to the source of the original packet: hop limit exceeded, unreachable node, a Parameter Problem about the Tunnel Encapsulation Limit option, which INET does not send, and packet too big. Section 8.2 reports the first three as a Destination Unreachable with code 3 (address unreachable), and a packet too big as a Packet Too Big with the reported MTU (maximum transmission unit) minus the tunnel headers, sent only if the original packet is larger than the IPv6 minimum link MTU of 1280 bytes. Section 7.1 (a) keeps the reported MTU at 1280 bytes or more. handleTunnelIcmpErrorIndication() does that for Destination Unreachable, Packet Too Big and Time Exceeded with code 0 (hop limit exceeded), and drops every other error about a tunnel packet with a warning. Every Destination Unreachable code counts as an unreachable node: about a forwarded packet INET sends only code 0 (no route) and code 3 (address resolution failed). The ICMPv6 message quotes at most 1280 bytes, so the size of the original packet comes from the Payload Length of the quoted inner header. If this node is itself the source of the original packet, the indication is processed again for the inner header, as before. New tests in tests/module, each failing before this commit: IPv6_tunnel_packet_too_big.test, IPv6_tunnel_packet_too_big_small.test and IPv6_tunnel_unreachable.test. Change: src.networklayer.ipv6.Ipv6 | behavior.change.fix | test whatsnew | ipv6-tunnel-icmp-errors
…eader A node that was both the entry point of an Ipv6TunnelInterface and the source of the original packet passed an ICMPv6 (Internet Control Message Protocol for Internet Protocol version 6) Packet Too Big about its tunnel packet to the transport protocol with the MTU (maximum transmission unit) of the tunnel packet, which leaves no room for the 40-byte tunnel header. A Transmission Control Protocol (TCP) connection with Path MTU Discovery (pmtudEnabled) then stalled: on a Packet Too Big reporting 1400, TCP lowered its maximum segment size (MSS) to 1340, every full segment made a 1440-byte tunnel packet that the 1400-byte link refused again, and no data arrived in 10 s. RFC (Request for Comments) 2473 (Generic Packet Tunneling in IPv6) Section 8.2 gives the source of the original packet the reported MTU minus the tunnel headers, and Section 7.1 (a) keeps it at 1280 bytes or more. handleTunnelIcmpErrorIndication() already applies that translation when it relays the message to another node; it now applies it to the indication that it processes again for a local source. The 1280-byte condition of Section 8.2 is not applied here: it decides whether a message is sent to another node, while a local transport protocol only receives the MTU. tests/module/IPv6_tunnel_packet_too_big_tcp.test reproduces it; with this commit the MSS is 1300 and all 100000 bytes arrive. Change: src.networklayer.ipv6.Ipv6 | behavior.change.fix | test whatsnew | ipv6-tunnel-icmp-errors
| if (rt->isLocalAddress(innerHeader->getSrcAddress())) { | ||
| // this node is also the source of the original packet | ||
| if (packetTooBig) | ||
| errorInd->setMtu(innerMtu); | ||
| handleIcmpErrorIndication(indication); | ||
| return; |
There was a problem hiding this comment.
🔴 Tunnel errors abort local TCP connections
For a locally sourced tunnel packet, handleTunnelIcmpErrorIndication forwards Destination Unreachable with its outer code unchanged. TcpConnection::processIcmpv6Error aborts connection setup for port-unreachable or administratively prohibited codes. The tunnel error must reach TCP as address unreachable, not a port or policy failure.
Learn more
A tunnel error describes the outer route rather than the transport endpoint in the inner packet. The local-source branch sends the original indication directly into IPv6 again, leaving a Destination Unreachable error's code unchanged. TcpConnection::processIcmpv6Error treats port-unreachable and administratively prohibited codes as hard errors during connection setup. For a remote original source, this method already creates a new Destination Unreachable with address-unreachable code 3.
Example: Host A opens TCP over its own IPv6 tunnel. An outer router sends Destination Unreachable, code 4 (port unreachable), quoting its tunnel packet. Host A passes code 4 to TCP, which closes the pending connection rather than reporting address unreachable for the tunnel path.
Recommended fix: Translate allowed non-PTB errors to address-unreachable code 3 for the local-source branch as well, before calling handleIcmpErrorIndication. Cover both local and remote sources with a code-4 or code-1 outer error.
Was this helpful? React with 👍 or 👎 to provide feedback.
| if (rt->isLocalAddress(innerHeader->getSrcAddress())) { | ||
| // this node is also the source of the original packet | ||
| if (packetTooBig) | ||
| errorInd->setMtu(innerMtu); | ||
| handleIcmpErrorIndication(indication); | ||
| return; |
There was a problem hiding this comment.
🟡 Spurious size errors for local tunnel sources
For a locally sourced inner packet of at most 1280 bytes, handleTunnelIcmpErrorIndication forwards Packet Too Big. The remote-source path suppresses that error, but the local-source return bypasses its size check. Local transports receive an error for a packet the tunnel must fragment instead.
Learn more
Packet Too Big on the outer tunnel path must not be reported for an inner IPv6 packet no larger than the minimum link MTU of 1280 bytes. The remote-source path checks the original packet's IPv6 payload length before generating a new error, but the local-source branch forwards the original indication immediately. The MTU adjustment does not suppress the indication.
Example: A host sends a 1248-byte IPv6 packet through its own tunnel across a 1280-byte link. The 1288-byte outer packet triggers Packet Too Big. The host's UDP module receives the translated error even though the entry point must handle fragmentation without reporting this error to UDP.
Recommended fix: Apply the inner-packet size guard before the local-versus-remote split for Packet Too Big, and add a local-source counterpart to the existing small-packet tunnel test.
Was this helpful? React with 👍 or 👎 to provide feedback.
A router that forwards a User Datagram Protocol (UDP) or Transmission Control Protocol (TCP) packet into an
Ipv6TunnelInterfacestopped the simulation when an ICMPv6 (Internet Control Message Protocol for Internet Protocol version 6) error about the tunnel packet came back. The tunnel entry point now reports the error to the source of the original packet, as RFC (Request for Comments) 2473 (Generic Packet Tunneling in IPv6) Section 8 requires. A node that is itself the entry point and the source of the original packet gets the reported MTU (maximum transmission unit) minus the 40-byte tunnel header, for example 1360 instead of 1400, so its TCP no longer stalls. Results change only where an ICMPv6 error about a tunnel packet arrives: on a router, where the simulation stopped before, and on a node that is entry point and source, where the transport protocol now sees the smaller MTU. The tunnels that Mobile IPv6 (MIPv6) and Proxy Mobile IPv6 (PMIPv6) create take the same code path; no configuration with them was run with a tunnel error.Closes #1293
The problem
Ipv6::handleIcmpErrorIndication()(src/inet/networklayer/ipv6/Ipv6.cc:306-339on master) pops the quoted IPv6 header and dispatches the indication by its next header. For a tunnel packet the next header is IPv6, so the indication came back toIpv6, which popped the inner header and dispatched it again, to the inner transport protocol.tests/module)IPv6_tunnel_packet_too_big: router entry point, a Packet Too Big reporting 1400 about a 1488-byte tunnel packetUnknown protocol: protocolId = 69, protocolName = udpat borderAIPv6_tunnel_packet_too_big_small: the same with a 1248-byte original packet and a 1280-byte linkIPv6_tunnel_unreachable: the tunnel exit point does not existIPv6_tunnel_packet_too_big_tcp: host entry point, TCP with Path MTU Discovery (pmtudEnabled) and a maximum segment size (MSS) of 1380The commits
ipv6: fix: relay a tunnel packet's ICMPv6 error to the original source: the entry point reports the errors that RFC 2473 Section 8.1 lists to the source of the original packet, as Section 8.2 says, and drops the others; a local source keeps master's path. Tests:IPv6_tunnel_packet_too_big,IPv6_tunnel_packet_too_big_small,IPv6_tunnel_unreachable.ipv6: fix: give a local tunnel source the MTU left after the tunnel header: the indication for a local source carries the translated MTU as well. Test:IPv6_tunnel_packet_too_big_tcp.Architectural surface
A new protected virtual method
Ipv6::handleTunnelIcmpErrorIndication(Indication *)in theINET_APIclassIpv6. It is virtual likehandleIcmpErrorIndication()next to it, so that a subclass can change which errors reach the source of the original packet, for example when it sends the Tunnel Encapsulation Limit option.Ipv6now handles an ICMPv6 error about an IPv6-in-IPv6 packet itself instead of dispatching it to a transport protocol. It sends its reports through the existingIcmpv6::sendErrorMessage(). No NED (Network Description) parameter, packet format or feature descriptor changes.Verification
Release build (
make MODE=release):The four new tests fail on master and pass on this branch; the existing
IPv6_tunnel.testpasses on both. At the first commit, its three tests andIPv6_tunnel.testpass.Full suites, release, on master 93210f4 and at both commits of this branch:
examples/ipv6/nclientsETHandPPPinmipv6-refactoring.csv; the errors are rows whose optional features are disabled in this build. No fingerprint moves.tcp_*,ConvolutionalCoder12/34,EtherHost_lifecycle,ExternalProcess_3,Ieee80211BitDomain/SymbolDomain,Ieee8021d-Rstp/Stp,IPv6_packet_too_big,MIPv6_tcp_handover,PacketGate_1,UDPSocket_1).IPv6_packet_too_bigis about a router's Packet Too Big for a forwarded packet without a tunnel; it fails on master in release builds only and passes in debug.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 at the tip of this branch, and the new tests fail on master in debug too. The first commit was built in release only.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
Icmpv6discards it before it reachesIpv6("Transport protocol 44 not registered, packet dropped"), so this fix does not see it.Landing order
git merge-treeagainst the heads of the open pull requests #1228, #1232, #1252, #1256 and #1264 mergesIpv6.ccandIpv6.hcleanly, including #1264, which also edits both files. The only conflict isWHATSNEW, where each adds an item with the same number; the pull request that lands later renumbers its item.