mipv6: send mobility signaling to the next hop instead of to the whole link - #1262
adamgeorge309 wants to merge 2 commits into
Conversation
A locally-originated unicast datagram that carries a pinned output interface went to the link layer with dest = FF-FF-FF-FF-FF-FF. Every Neighbour Discovery message pins its output interface, so a solicited Neighbour Advertisement and a Neighbour Unreachability Detection probe both left the node as an Ethernet broadcast, although the neighbour was in the Neighbour Cache. Every node on the link then received them, and a router forwarded the advertisement and answered it with a spurious ICMPv6 Redirect. RFC 4861 Section 7.2.4 requires the solicited advertisement to be unicast to the soliciting node, and Section 5.2 says where the link-layer address comes from: "Once the IP address of the next-hop node is known, the sender examines the Neighbor Cache for link-layer information about that neighbor." The multicast half of the same branch was corrected in 3be7618; the unicast half was left on the broadcast address. Pinning an output interface makes the Ipv6 module skip next-hop determination, so it has no next-hop address to look up. Neighbour Discovery therefore states the next hop it already knows -- an ND message is by definition addressed to a neighbour on the link it goes out on -- and datagramLocalOut() takes the link-layer address from the cache when a next hop is stated. Resolving the destination instead would be wrong. A pinned interface does not imply an on-link destination: PIM-SM pins one for the unicast it sends toward the rendezvous point, and a mobile node keeps a cache entry for its home agent after it has roamed, so the entry addresses a node that is no longer on the link. Both keep the previous behaviour, because neither states a next hop. Not repaired here: an advertisement answering a unicast solicitation that carried no Source Link-Layer Address option still goes out as a broadcast, because the responder has no cache entry to use. RFC 4861 Section 7.2.4 says such a node has to resolve the neighbour first, and the TODO in sendSolicitedNa() records that this is not implemented. This commit re-records 18 fingerprint rows: 14 in examples.csv, one per IPv6 configuration that performs address resolution, and 4 in mipv6-refactoring.csv, the second row that file keeps for four of those configurations. Their Neighbour Discovery frames are now addressed to one neighbour instead of to the whole link: a switch forwards them to one port, and on 802.11 the other stations discard them. The nodes that no longer receive them lose their reception events, so the event times, module paths, lengths and extra data (tplx) and the inter-node times, node paths and lengths (~tNl) move in the 14 examples.csv rows. The inter-node packet bytes (~tND, in 9 of those rows) and the message contents (~tNlb, the 4 mipv6-refactoring.csv rows) move with the destination address in the Medium Access Control (MAC) header. The display string and figure ingredients (tyf) were excluded from the run and are carried over unchanged. On origin/master 49e1fa0 the whole suite (./fingerprinttest -s -F tyf) has 0 failures; with this change it fails exactly these 18 rows before the re-record, so no configuration without IPv6 address resolution moves. Change: src.networklayer.ipv6 | behavior.change.fix | fingerprint test
Mobile Internet Protocol version 6 (Mobile IPv6, MIPv6) pins the output interface of the Binding Update (BU), the Care-of Test Init (CoTI), the Binding Acknowledgement (BA) and the Binding Refresh Request, but states no next hop. A pinned interface makes the Ipv6 module skip next-hop determination, and with no next hop Ipv6::datagramLocalOut() addresses the frame to FF-FF-FF-FF-FF-FF. On an 802.11 link the access point relays such a frame back into its cell, so every node on the link receives a mobile node's BU to its home agent and to its correspondent node, and its CoTI. The home agent's and the correspondent node's BA go out as Ethernet broadcasts. Request for Comments (RFC) 4861 Section 5.2: "Once the IP address of the next-hop node is known, the sender examines the Neighbor Cache for link-layer information about that neighbor." The next hop of an on-link destination is the destination; otherwise it is a router. Mipv6 now states the next hop, which the Ipv6 module looks up in the Neighbour Cache since #1152 ("ipv6: fix: address a pinned unicast datagram from the Neighbour Cache"). Neighbour Discovery passes its destination as the next hop, because a Neighbour Discovery message always goes to a neighbour; a mobility message's destination need not be on-link, so Mipv6 takes the next hop of the longest matching route through the pinned interface, or the destination itself when that route is on-link. A link-local destination is its own next hop (RFC 4861 Section 5.1). Ipv6RoutingTable::doLongestPrefixMatch() is not used because it may return a route through another interface, whose next hop is not a neighbour on the pinned one. For a mobile node away from home the result is the default router on the foreign link: the Router Advertisement that formed the care-of address installed its default route, and the handover deleted the routes of the previous link. It is not the destination's Neighbour Cache entry, which a mobile node keeps for its home agent after it has roamed. To reproduce, run examples/ipv6/mipv6 -c Handover with a PcapRecorder on MN[0] (**.MN[*].numPcapRecorders = 1, **.checksumMode = "computed", **.fcsMode = "computed"): the Binding Update (BU) to the home agent leaves with destination address FF-FF-FF-FF-FF-FF, and the access point sends it back into the cell 1 ms later. Not repaired here: when the next hop has no Neighbour Cache entry, the Ipv6 module still falls back to the broadcast address instead of resolving it. In MIPv6_route_optimization.test the home agent's Binding Acknowledgement (BA) leaves this way, because the home agent has not yet resolved its neighbouring router. In the module test network the mobile node also sends Care-of Test Init (CoTI) messages to the home agent's link-local address from the foreign link; that address is not a neighbour there, so they stay broadcasts, and the new test excludes link-local destinations. Starting return routability toward a link-local address is a separate defect of Mipv6: the address is valid only on the home link, so the CoTI cannot reach it from the foreign link. tests/module/MIPv6_signaling_unicast_mac.test covers registration, return routability and de-registration, and fails without this change. This commit re-records six fingerprint rows, one in examples.csv and one in mipv6-refactoring.csv for each of the three MIPv6 configurations: examples/ipv6/mipv6 Handover and RouteOptimizationTwoCNs, and examples/ipv6/mipv6roaming Roaming. Their mobility frames are addressed to one neighbour instead of the whole link: the access point no longer relays a copy into the cell, the other nodes lose those reception events, and each frame the access point delivers into the cell becomes a unicast frame and gains an 802.11 acknowledgement. That moves the event times, module paths, lengths and extra data (tplx) and the inter-node times, node paths and lengths (~tNl); the inter-node packet bytes (~tND) and message contents (~tNlb) also move with the destination address in the Medium Access Control (MAC) header. The whole suite (./fingerprinttest -s -F tyf) fails exactly these six rows before the re-record, so no other configuration that ran moves in those ingredients; the 62 rows of disabled features did not run. The display string and figure ingredients (tyf) were excluded from the run and are carried over. This change moves them too, in the three examples.csv rows, but the recorded values did not match before it either. ./fingerprinttest -s -m ipv6/mipv6 examples.csv gives, for Handover, e6fe-746f on the parent commit and 53af-420e with this change against the recorded 44ef-1a45; for RouteOptimizationTwoCNs, fd98-4698 and 2ad8-5c7d against ed3e-17fa; for Roaming, 3588-8594 and bc16-30b9 against afae-2b3c. The statistical baselines of these three configurations were not run. Change: src.mipv6.Mipv6 | behavior.change.fix | fingerprint test whatsnew
There was a problem hiding this comment.
Devin Review found 1 potential issue.
2 flags not posted on this PR by your GitHub settings — view them in Devin Review. (Configure)
| for (int i = 0; i < rt6->getNumRoutes(); i++) { | ||
| const Ipv6Route *route = rt6->getRoute(i); | ||
| if (route->getInterface() == nullptr || route->getInterface()->getInterfaceId() != interfaceId) | ||
| continue; | ||
| if (!destAddr.matches(route->getDestPrefix(), route->getPrefixLength())) | ||
| continue; | ||
| if (route->getExpiryTime() != 0 && simTime() > route->getExpiryTime()) // 0 means infinity | ||
| continue; | ||
| // an on-link destination is its own next hop | ||
| return route->getNextHop().isUnspecified() ? destAddr : route->getNextHop(); |
There was a problem hiding this comment.
🟡 Mobility signaling ignores redirected next hops
After an IPv6 Redirect, getNextHopOnInterface still selects the original route's router. processRedirectPacket updates the destination cache, which this lookup ignores. Mobility messages can miss their destination when the former router stops forwarding.
Learn more
An IPv6 Redirect changes the next hop for one destination by updating the destination cache, not the routing table. The normal IPv6 output path reads that cache in determineOutputInterface. Mobility messages pin an interface, bypassing that path, and this lookup selects the old route instead. Thus a mobility packet can take a different first hop from ordinary packets to the same destination.
Example: A correspondent node reaches a mobile node's care-of address through router A. Router A redirects that destination to router B on the same link. Ordinary packets use B, but a later Binding Acknowledgement still uses A; if A stops forwarding, the acknowledgement does not arrive.
Recommended fix: In getNextHopOnInterface, consult lookupDestCache before the route scan and accept its next hop only if its cached interface matches interfaceId. Fall back to the longest matching route on the pinned interface otherwise, and test a redirected destination with a subsequent pinned mobility message.
Was this helpful? React with 👍 or 👎 to provide feedback.
Mobile Internet Protocol version 6 (Mobile IPv6, MIPv6) signaling sent on a pinned output interface
now carries the link-layer address of its next hop instead of FF-FF-FF-FF-FF-FF. The branch is built
on #1152, which makes the Ipv6 module take the link-layer address from the Neighbour Cache when the
sender states a next hop; this pull request makes Mipv6 state it. Merge #1152 first. Until then this
pull request also shows #1152's commit 222173a, and only the last commit is new.
Closes #1261
The problem
Mipv6::sendMobilityMessageToIPv6Module()pins the output interface of the Binding Update (BU), theCare-of Test Init (CoTI), the Binding Acknowledgement (BA) and the Binding Refresh Request, and
states no next hop, so
Ipv6::datagramLocalOut()sends them to the broadcast address. On 802.11 theaccess point relays each such broadcast back into its cell, so the mobile node receives its own
frames again.
examples/ipv6/mipv6 -c Handoverwith**.MN[*].numPcapRecorders = 1,**.checksumMode = "computed"and**.fcsMode = "computed", captured atMN[0](before:222173a, the head of #1152; after: this pull request):
The return home is 1.1 s earlier with the change because the two runs diverge after the first
changed frame.
The fix
Pinning an output interface skips next-hop determination, so the Ipv6 module has no address to look
up in the Neighbour Cache. #1152 explains why it must not resolve the destination instead: a mobile
node keeps its cache entry for the home agent after it has roamed.
Mipv6 now states the next hop (Request for Comments (RFC) 4861 Section 5.2): the next hop of the
longest matching route through the pinned interface, or the destination itself when that route is
on-link or the destination is link-local.
Ipv6RoutingTable::doLongestPrefixMatch()is not usedbecause it may return a route through another interface. For a mobile node away from home the
result is the default router of the foreign link: the handover deletes the previous link's routes,
and the Router Advertisement that formed the care-of address installs the new default route.
Architectural surface
NextHopAddressReqtag on the datagrams whose output interface it pins; ipv6: address a pinned unicast datagram from the Neighbour Cache #1152gives that tag its meaning for a pinned interface.
Mipv6::getNextHopOnInterface(); no other class calls it.Acknowledgement (BA) and Binding Refresh Request frames changes. No packet format, Network
Description (NED) parameter, signal, module interface or
.oppfeaturesentry changes, and nosealed path is touched.
WHATSNEW: item 17 of the backward incompatible changes, because MIPv6 simulation trajectorieschange.
doc/project/enforcement/check-architecture.sh src/inet/networklayer/mipv6passes.check-naming.sh src/inet/networklayer/mipv6reports the gate namesfromIPv6andtoIPv6inMipv6.ned, which this pull request does not touch.Verification
Base: #1152 (222173a) on the merge base 49e1fa0. "origin/master" below means 49e1fa0;
origin/master has not changed
src/since then (it is now 4eb3bb4). Each set of runs followsmake -j4 MODE=release(orMODE=debugfor the debug runs) at the repository root; module testsrun in
tests/module, protocol tests intests/protocol/ipv6, fingerprints intests/fingerprint.tests/module/MIPv6_signaling_unicast_mac.test(new): the mobile node moves home, abroad and homeagain; no BU, BA, Home Test Init (HoTI), CoTI, Home Test (HoT) or Care-of Test (CoT) to a global
address may leave with a broadcast destination address, and the BU from the foreign link must go
to the foreign router. It fails on the base and passes with this change.
inet_run_module_tests -m release --no-build -l ERROR(all module tests): 347 tests and 46failures on the base; 348 tests and the same 46 failures with this change:
MIPv6_tcp_handover,IPv6_packet_too_big, 34 Transmission Control Protocol (TCP) tests,Ieee80211BitDomain,Ieee80211SymbolDomain,ConvolutionalCoder12,ConvolutionalCoder34,Ieee8021d-Stp(Spanning Tree Protocol),
Ieee8021d-Rstp(Rapid Spanning Tree Protocol),PacketGate_1,UDPSocket_1,ExternalProcess_3,EtherHost_lifecycle. The same 46 fail on origin/master.inet_run_module_tests -m debug --no-build -l ERROR -f 'IPv6|PIM|Pim|pim': 42 of 42 pass. Thefilter selects the Internet Protocol version 6 (IPv6) and Mobile IPv6 tests, and the Protocol
Independent Multicast (PIM) tests, because PIM also sends on a pinned output interface
(
PimBase.cc:160,PimSm.cc:1692) through the Ipv6 path that ipv6: address a pinned unicast datagram from the Neighbour Cache #1152 changes; the two InternetProtocol version 4 (IPv4) PIM tests match the filter as well.
inet_run_protocol_tests -m releaseintests/protocol/ipv6: 26 of 27 pass on the base and withthis change;
Rfc8200OverlappingFragmentsfails in both, as it does on origin/master. In debug,27 of 27 pass.
./fingerprinttest -s -F tyf(no CSV argument, all rows): on the base 0 failures and 62 errors;with this change 6 failures and the same 62 errors; after the re-record 0 failures and the same
62 errors. The 62 errors are rows of disabled features: VoipStream (40, including the
Differentiated Services (diffserv) Voice over IP configurations), TcpLwip (14), the OpenSceneGraph
(OSG) visualizer (7) and Z3 gate scheduling (1). The 6 re-recorded rows:
examples.csv:examples/ipv6/mipv6HandoverandRouteOptimizationTwoCNs,examples/ipv6/mipv6roamingRoaming, ingredientstplx(event times, module paths, lengthsand extra data),
~tNl(inter-node times, node paths and lengths) and~tND(inter-node times,node paths and packet bytes)
mipv6-refactoring.csv: the same three configurations,~tNlb(with message contents)The mobility frames go to one neighbour: the access point no longer relays a copy into the cell,
the other nodes lose those reception events, and each frame the access point delivers into the
cell becomes a unicast frame and gains an 802.11 acknowledgement. This moves the times, paths,
lengths and extra data. The packet bytes and message contents move with the destination address in
the Medium Access Control (MAC) header.
tyf(display strings and figures) was excluded from therun and is carried over. This change moves it too in the three
examples.csvrows, but therecorded values did not match before it either:
./fingerprinttest -s -m ipv6/mipv6 examples.csvgives
tyfmipv6Handover44ef-1a45e6fe-746f53af-420emipv6RouteOptimizationTwoCNsed3e-17fafd98-46982ad8-5c7dmipv6roamingRoamingafae-2b3c3588-8594bc16-30b9Statistical baselines: not run. The statistics repository (inet-framework/statistics) holds
results for the three configurations whose fingerprints move,
examples/ipv6/mipv6Handoverand
RouteOptimizationTwoCNsandexamples/ipv6/mipv6roamingRoaming; they are not re-recordedhere.
doc/project/enforcement/check-commits.shandcheck-classification.shon the new commit pass.check-source-seals.sh --base origin/masterpasses.check-naming.sh --base origin/masterandcheck-interfaces.shreport the same findings as on origin/master, none in a file this changetouches.
Not addressed here
address instead of resolving it (the fallback ipv6: address a pinned unicast datagram from the Neighbour Cache #1152 keeps). In
MIPv6_route_optimization.testthehome agent's Binding Acknowledgement (BA) leaves this way, because the home agent has not yet
resolved its neighbouring router.
link-local address and sends Care-of Test Init (CoTI) messages to it from the foreign link. They
have no neighbour to address and stay broadcasts, so the new test excludes link-local
destinations. Starting return routability toward a link-local address is a separate defect of
Mipv6: the address is valid only on the home link, so the CoTI cannot reach it from the foreign
link.