What happens
A mobile node that has just moved to a foreign network discards every packet it sources from
its home address until its home registration completes, logging:
Using HoA instead of CoA... dropping datagram
Meanwhile the home agent has already started forwarding: it creates its tunnel and begins
tunneling the correspondent node's traffic as soon as it accepts the Binding Update, whereas
the mobile node creates its own reverse tunnel only when the Binding Acknowledgement arrives.
So the mobile node is receiving tunneled traffic that it cannot answer, and the answers are
lost rather than delayed.
How to reproduce
In the stock example, no branch or showcase needed:
cd examples/ipv6/mipv6roaming
opp_run -r 0 -m -u Cmdenv -c Roaming -n ../..:../../../src -l ../../../src/INET \
--cmdenv-express-mode=false --cmdenv-log-prefix="%t %C: " omnetpp.ini \
| grep "Using HoA instead of CoA"
Three datagrams are discarded, at t = 24.503515 s (two) and t = 25.000985 s, all during the
first registration. They are the mobile node's first two ICMPv6 echo replies to the
correspondent node and its first Home Test Init. The home agent created its tunnel at
t = 24.208307 s; the mobile node creates its own at t = 25.209873 s.
Losing the Home Test Init also delays return routability by a retransmission timeout, so the
cost is not only the lost data packets.
Verified on 1869032b71. The code below is byte-identical at 021485b99c, so the defect is
present unchanged on current master.
What the standard says
RFC 6275 Section 11.3.1:
For packets sent that are part of transport-level connections established while the mobile
node was at home, the mobile node MUST use its home address. [...] If a binding exists, the
mobile node SHOULD send the packets directly to the correspondent node. Otherwise, if a
binding does not exist, the mobile node MUST use reverse tunneling.
Reverse tunneling is a MUST here, and the same section defines what the tunnel looks like:
The Source Address in the tunnel packet is the primary care-of address as registered with
the home agent.
Discarding is not among the treatments the standard describes.
Cause
Mipv6::datagramLocalOutHook() calls requestTunnelOutputInterface(), which pins the reverse
tunnel as the output interface. While no reverse tunnel exists yet, it pins nothing, so the
datagram is routed normally onto the foreign link and reaches the last-resort guard in
Ipv6::resolveMACAddressAndSendPacket() (src/inet/networklayer/ipv6/Ipv6.cc:578-592):
if (mipv6Data && ipv6Data
&& ipv6Header->getSrcAddress() == mipv6Data->getMNHomeAddress()
&& !ipv6Data->getGlobalAddress(Ipv6InterfaceData::CoA).isUnspecified())
{
EV_WARN << "Using HoA instead of CoA... dropping datagram" << endl;
delete packet;
numDropped++;
return;
}
The guard itself is right: a home address is not a topologically correct source on a foreign
link, and the guard correctly exempts tunnel interfaces, which legitimately carry
home-address-sourced inner packets. What is wrong is that traffic which merely arrived early
reaches it at all.
Suggested fix
Hold such a datagram while a home registration is in flight and send it into the reverse tunnel
once the tunnel exists, instead of letting it reach the guard. The netfilter QUEUE verdict and
reinjectQueuedDatagram() already provide the mechanism.
Holding must be bounded, and the registration alone does not bound it: a Binding Update that is
never acknowledged is retransmitted indefinitely and its binding update list entry never
expires. A cap on how much may be held per home agent is needed as well, so that a home agent
which stops answering does not turn a visible drop into an unbounded silent backlog. Note also
that the datagrams would be borrowed pointers into the IPv6 module's netfilter queue, which
Ipv6::flush() frees on stop and crash without notifying its hooks.
Creating the reverse tunnel when the Binding Update is sent rather than when it is
acknowledged would avoid the delay, but RFC 6275 Section 11.3.1 defines the tunnel's outer
source as the care-of address "as registered with the home agent": before the acknowledgement
nothing is registered, and the datagrams would be tunneled to a home agent that has no binding
for them.
Note also that the window is opened by the home agent's fixed delay before it sends the Binding
Acknowledgement (#1194). Shortening that window is not a substitute: the discarding is wrong
however short the window is, including zero.
Related
What happens
A mobile node that has just moved to a foreign network discards every packet it sources from
its home address until its home registration completes, logging:
Meanwhile the home agent has already started forwarding: it creates its tunnel and begins
tunneling the correspondent node's traffic as soon as it accepts the Binding Update, whereas
the mobile node creates its own reverse tunnel only when the Binding Acknowledgement arrives.
So the mobile node is receiving tunneled traffic that it cannot answer, and the answers are
lost rather than delayed.
How to reproduce
In the stock example, no branch or showcase needed:
Three datagrams are discarded, at t = 24.503515 s (two) and t = 25.000985 s, all during the
first registration. They are the mobile node's first two ICMPv6 echo replies to the
correspondent node and its first Home Test Init. The home agent created its tunnel at
t = 24.208307 s; the mobile node creates its own at t = 25.209873 s.
Losing the Home Test Init also delays return routability by a retransmission timeout, so the
cost is not only the lost data packets.
Verified on
1869032b71. The code below is byte-identical at021485b99c, so the defect ispresent unchanged on current master.
What the standard says
RFC 6275 Section 11.3.1:
Reverse tunneling is a MUST here, and the same section defines what the tunnel looks like:
Discarding is not among the treatments the standard describes.
Cause
Mipv6::datagramLocalOutHook()callsrequestTunnelOutputInterface(), which pins the reversetunnel as the output interface. While no reverse tunnel exists yet, it pins nothing, so the
datagram is routed normally onto the foreign link and reaches the last-resort guard in
Ipv6::resolveMACAddressAndSendPacket()(src/inet/networklayer/ipv6/Ipv6.cc:578-592):The guard itself is right: a home address is not a topologically correct source on a foreign
link, and the guard correctly exempts tunnel interfaces, which legitimately carry
home-address-sourced inner packets. What is wrong is that traffic which merely arrived early
reaches it at all.
Suggested fix
Hold such a datagram while a home registration is in flight and send it into the reverse tunnel
once the tunnel exists, instead of letting it reach the guard. The netfilter
QUEUEverdict andreinjectQueuedDatagram()already provide the mechanism.Holding must be bounded, and the registration alone does not bound it: a Binding Update that is
never acknowledged is retransmitted indefinitely and its binding update list entry never
expires. A cap on how much may be held per home agent is needed as well, so that a home agent
which stops answering does not turn a visible drop into an unbounded silent backlog. Note also
that the datagrams would be borrowed pointers into the IPv6 module's netfilter queue, which
Ipv6::flush()frees on stop and crash without notifying its hooks.Creating the reverse tunnel when the Binding Update is sent rather than when it is
acknowledged would avoid the delay, but RFC 6275 Section 11.3.1 defines the tunnel's outer
source as the care-of address "as registered with the home agent": before the acknowledgement
nothing is registered, and the datagrams would be tunneled to a home agent that has no binding
for them.
Note also that the window is opened by the home agent's fixed delay before it sends the Binding
Acknowledgement (#1194). Shortening that window is not a substitute: the discarding is wrong
however short the window is, including zero.
Related